最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using Webpack externals and still allow ES6 style imports? - Stack Overflow

programmeradmin1浏览0评论

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',
      monjs2: 'react',
      monjs: '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": ["/*"],
       "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 ponent test
const Hello = props => {
  return (
    <div>hello world</div>
  )
}

// class ponent 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 ment 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 ment 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 ponents will be used in future projects and I want to keep this as modular and portable as possible.

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',
      monjs2: 'react',
      monjs: '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./*"],
       "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 ponent test
const Hello = props => {
  return (
    <div>hello world</div>
  )
}

// class ponent 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 ment 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 ment 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 ponents will be used in future projects and I want to keep this as modular and portable as possible.

Share Improve this question asked Sep 5, 2017 at 23:58 KevinKevin 3,6417 gold badges37 silver badges41 bronze badges 2
  • I haven't worked with modules yet so my ment 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 Commented Sep 6, 2017 at 7:09
  • I tried changing my code from import React from 'react' to const React = require('react') but I still get the same error. – Kevin Commented Sep 9, 2017 at 4:50
Add a ment  | 

1 Answer 1

Reset to default 5

It turns out I was over-plicating webpack externals.

Changing from:

externals: {
    react: {
      root: 'React',
      monjs2: 'react',
      monjs: '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./webpack/webpack/issues/1275 helped me out.

发布评论

评论列表(0)

  1. 暂无评论