Search code examples
javascriptreactjswebpackbabeljswebpack-loader

External React component library JSX Babel wont compile


I'm trying to extract certain compoennts in my React Application to a separate reusable component library.

What I've done, is cloned this project: https://rinsejs.io/ and subsequently referenced the github repo in my main projects package.json

entry in package json of core project

 "react-sharedlib": "git+ssh://[email protected]/myrepos/react-sharedlib.git#master",

Webpack.config inside react-sharedlib

// Path is in Node for free and will make simple resolving of directories no
// matter which part of your file system your library lives in
const path = require('path');

// Webpack is just a bunch of keys on module.exports!
module.exports = {
    // This is where our app starts. This is why we hnpm install --save-dev [email protected] done all this importing
    // and exporting, to get to here
    entry: './src/index.js',
    // module (I know it's a bit weird to hanpm install --snpm install --save-dev [email protected] [email protected] module.exports.module) is where we
    // define all the rules for how webpack will deal with thing.
    module: {
        // rules takes an array, each item containing the respective rules
        rules: [
            {
                // First up, our JavaScript rules.
                // If you want to use the .jsx extension, you can change this line to
                // test: /\.jsx?$/,
                // The ? in the regex just means "optional"
                test: /\.js$/,
                // Don't bother spending time transpiling your installed packages
                // exclude: /node_modules/,
                // This is where we tell webpack to use babel to transpile our JS.
                // The configuration can go here, but in this case it's in ./babelrc.js
                use: {
                    loader: 'babel-loader',
                },
            },
            {
                // I haven't used SCSS in the base example, but it's here for you if you
                // want! If you want to use CSS, you can change this next like's regex to
                // /\.(css|scss)$/ or even just /\.css$/
                test: /\.scss$/,
                use: [
                    // These three libraries are commonly used together to turn Sass into
                    // CSS, then be able to load the CSS directly with imports. From there
                    // It gets put in the DOM for you.
                    { loader: 'style-loader' },
                    { loader: 'css-loader' },
                    { loader: 'sass-loader' },
                ],
            },
            {
                // Some image formats so you can import images
                test: /\.(png|gif|jpg|svg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        limit: 50000,
                    },
                },
            },
        ],
    },
    // Here we define explicitly the file types we intend to deal with
    resolve: {
        extensions: ['.scss', '.js', '.json', '.png', '.gif', '.jpg', '.svg'],
    },
    // This is where we define how everything gets output.
    // dist is a common output folder, and it should be gitignored. The build can
    // be run after publishing so you don't wind up with it in source control
    output: {
        path: path.resolve(__dirname, 'dist/'),
        publicPath: '',
        // You can do fun things here like use the [hash] keyword to generate unique
        // filenames, but for this purpose rinse.js is fine. This file and path will
        // be what you put in package.json's "main" field
        filename: 'rinse.js',
        // This field determines how things are importable when installed from other
        // sources. UMD may not be correct now and there is an open issue to fix this,
        // but until then, more reading can be found here:
        // https://webpack.js.org/configuration/output/#output-librarytarget
        libraryTarget: 'umd',
    },
};

Babel config inside shared-lib:

{
    "presets": ["@babel/env", "@babel/preset-react", "es2015", "react"],
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
 }

Package.JSON inside shared-lib:

{
  "name": "react-sharedlib",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "dependencies": {
    "@babel/preset-react": "^7.0.0",
    "babel-core": "^6.4.5",
    "babel-loader": "^6.2.1",
    "babel-preset-es2015": "^6.3.13"
  },
  "devDependencies": {
    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
    "babel-preset-react": "^6.3.13"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/myrepos/react-sharedlib.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/myrepos/react-sharedlib/issues"
  },
  "homepage": "https://github.com/myrepos/react-sharedlib#readme"
}

When I try to build my project I get this error. (Which looks like a problem with babel in some capacity, not being able to reference the JSX syntax or needing a loader configured. Anyone any idea what I'm doing wrong here, or what other things to try? As you can see from my dependencies I've had a go at installing Babel loaders, but to no avail. I assume I may just be missing a piece of configuration somewhere to get it to recognise the HTML inside the JS file.

ERROR in /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/components/Button/Button.js 23:8
Module parse failed: Unexpected token (23:8)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|       // along without changing any of the contents. This is basically just creating
|       // a copy to pass along
>       return <ButtonWrapper {...props}>{props.children}</ButtonWrapper>;
| }
| 
 @ /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/components/Button/index.js 2:0-30 4:15-21
 @ /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/index.js
 @ ./app/App.js
 @ ./index.js

Latest version of React btw. Webpack 4.29.6

Update: ** Following on from the answer posted below, my shared library webpack.config.js file now contains this entry which unfortunately made no difference.

  rules: [
        {
            // First up, our JavaScript rules.
            // If you want to use the .jsx extension, you can change this line to
            // test: /\.jsx?$/,
            // The ? in the regex just means "optional"
            test: /\.js$/,
            // Don't bother spending time transpiling your installed packages
            // exclude: /node_modules/,
            // This is where we tell webpack to use babel to transpile our JS.
            // The configuration can go here, but in this case it's in ./babelrc.js
            use: {
                loader: 'babel-loader',
                options: {
                    babelrcRoots: [".", "node_modules/react-sharedlib"]
                }
            },
        }

CORE PROJECT .babelrc:

{
   "presets": ["@babel/env", "@babel/preset-react"],
   "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

SHARED PROJECT .babelrc:

{
    "presets": ["@babel/env", "@babel/preset-react", "es2015", "react"],
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
 }

Solution

  • By default, Babel assumes that .babelrc files in node_modules are ignored, because they were probably published on accident, and usually they reference plugins and presets that are in their devDependencies and thus probably aren't installed. The config could even be for a different version of Babel, so even if they were all installed, they still might not work.

    This means you need to either:

    • Tell Babel explicitly that node_modules/react-sharedlib is safe to load the config for.
    • Configure your application's Babel config to compile that specific node_modules/react-sharedlib.

    The first can be accomplished by specifying:

    babelrcRoots: [".", "node_modules/react-sharedlib"],
    

    in babel-loader's options.

    The second would require using a babel.config.js config file in your application, and exporting your project-wide plugins there, so that they apply to any file you pass to Babel.

    The Babel docs for config files are also a good place to review.