1
votes

I'm creating a Chrome Extension and I'm using React and Webpack.

Because this is a Chrome extension, I can use manifest.json to load React and ReactDOM into the browser well before any line of my own code get executed. My understanding is that:

  • the react.js lib loaded by manifest.json show up as globals, accessible via window.React
  • webpack externals can be configured so that React and ReactDOM doesn't get bundled

Here are my files:

webpack.config.js

module.exports = {

  entry: './index.js',
  output: {
    filename: 'skinny-bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader"
      }
    ]
  },

  externals: {
    react: {
      root: 'React',
      commonjs2: 'react',
      commonjs: 'react',
      amd: 'react'
    },
    'react-dom': {
      root: 'reactDOM'
    }
  }
}

manifest.json

{
  "manifest_version": 2,
  "name": "Test Application",
  "version": "3.2",
  "description": "testing",
  "short_name": "some test",

  "author": "blah blah",

  "content_scripts": [
     {
       "matches": ["https://www.google.com/*"],
       "js": [
         "react.js",
         "react-dom.js",

         "skinny-bundle.js"
       ],
       "run_at": "document_idle"
     }
   ]
}

index.js

import HelloGreeting from './HelloGreeting'    

ReactDOM.render(
    <HelloGreeting />,
    document.getElementById('cst')
)

HelloGreeting.js

// import React from 'react'   <----- here is my problem!!!

// functional component test
const Hello = props => {
  return (
    <div>hello world</div>
  )
}

// class component test
class HelloGreeting extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <ul>
        <li><Hello /></li>
        <li>hello universe</li>
      </ul>
    )
  }
}

export default HelloGreeting

Here lies my problem. I have a simple React Component called HelloGreeting that doesn't work if I keep the import React from 'react' line. If I comment out the import, it actually works because my guess is that webpack just ignores it because React has been defined in webpack externals. If I leave the import statement in , I get a "Uncaught TypeError: Cannot read property 'Component' if undefined" error, possibly because Webpack tries to bundle and messing up with window.React somehow. I made this guess because of what webpack emits with or without the import.

If I comment out the import, webpack emits a smaller bundle:

Hash: 26f1526e2554c828c050
Version: webpack 3.5.5
Time: 80ms
           Asset     Size  Chunks             Chunk Names
skinny-bundle.js  5.75 kB       0  [emitted]  main
   [1] ./HelloGreeting.js 2.5 kB {0} [built]
    + 1 hidden module

If I keep my import, my webpack emits a larger bundle:

Hash: 1fc9353f1fe6dd935744
Version: webpack 3.5.5
Time: 77ms
           Asset     Size  Chunks             Chunk Names
skinny-bundle.js  6.05 kB       0  [emitted]  main
   [1] ./HelloGreeting.js 2.71 kB {0} [built]
    + 2 hidden modules

My question is, what can I do to configure webpack so that I still have my ES6 style imports and still have webpack NOT bundle react.js?

I really want to keep the import statement because these components will be used in future projects and I want to keep this as modular and portable as possible.

1
I haven't worked with modules yet so my comment may be irrelevant, but if you expect import to be handled by the browser, it's not yet supported in extensions, moreover you use relative paths in a content script, not in an iframe, right? if so, the current URL is that of the webpage. - wOxxOm
I tried changing my code from import React from 'react' to const React = require('react') but I still get the same error. - Kevin

1 Answers

3
votes

It turns out I was over-complicating webpack externals.

Changing from:

externals: {
    react: {
      root: 'React',
      commonjs2: 'react',
      commonjs: 'react',
      amd: 'react'
    },
    'react-dom': {
      root: 'reactDOM'
    }
  }

to:

externals: {
    react: 'React',
    'react-dom': 'ReactDOM'
  },

...solved my problem. Now webpack ignores all of my React code and keeps my bundle small.

https://github.com/webpack/webpack/issues/1275 helped me out.