Search code examples
javascriptwebpackwebpack-2dexie

Using CommonsChunkPlugin without always needing to define webpackJsonp?


I have a project that makes use of a large bundle (dexie.js not that it's important to this question), that I'd like to 'split out' into it's own bundle that I can include manually, because it's only needed in a few of my entry point scripts.

Just so that you know: my webpack config uses multiple modules, with multiple (6) entry points, so this is a cut-down sample of my webpack.config.js:

{
context: path.join(__dirname, 'src'),
entry: {
    'js/contentscript.js' : './js/contentscript.js',
    'js/background.js'    : './js/background.js',
    'js/popup.js'         : './js/popup.js',
    'js/options.js'       : './js/options.js',
},
output: {
    path: path.join(__dirname, 'dist'), 
    filename: "[name]"
},
plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: "dexie",
        filename: "js/dexie.js",
        minChunks: function (module) {
            // this assumes your vendor imports exist in the node_modules directory
            return module.context && module.context.includes("node_modules/dexie");
        }
    }),
    ... // other non relevant plugins here
]
}

The problem is that I have no typical 'vendor' nor 'common' requirement, like many other projects to. It's only in a few cases that I want to include the js/dexie.js bundle.

eg. in options.html, I have this:

<script src="js/dexie.js"></script>
<script src="js/options.js"></script>

...but I do not want it to be used for popup.html, which I want to keep as this:

<script src="js/popup.js"></script>

And since this is also a WebExtensions project, I definitely don't want my content scripts to need it!

The problem is, that when I open popup.js, I get the error: Uncaught ReferenceError: webpackJsonp is not defined.

Is there any way -- without splitting this into more webpack modules -- so that the CommonsChunkPlugin will play nice with the entry points so that only the ones I want are affected by it?

The only solution I can think of, is to make another CommonsChunkPlugin that acts in the way that 'vendor' and 'common' is typically used. That is:

    new webpack.optimize.CommonsChunkPlugin({
        name: "dexie",
        filename: "js/dexie.js",
        minChunks: function (module) {
            // this assumes your vendor imports exist in the node_modules directory
            return module.context && module.context.includes("node_modules/dexie");
        }
    }),
    new webpack.optimize.CommonsChunkPlugin({
        name: "manifest",
        filename: "js/manifest.js",
        minChunks: Infinity
    }),

Unfortunately, this means I need to include js/manifest.js in all my scripts, and since this is a WebExtension, then that means I have to inject it into each content page...IMHO this is a terrible solution.

Any ideas on how to improve this? Am I using CommonsChunkPlugin incorrectly? Is there a better module I should be using? (I'm actually still coming to grips with webpack!)


Solution

  • I stumbled across this excellent answer by @prograhammer: https://stackoverflow.com/a/40416826/125525

    In it he made reference to the Externals plugin, which I'd not heard of before, and it neatly solves my problems. This is the description from the webpack site:

    For example, to include jQuery from a CDN instead of bundling it:

    index.html

    <script
      src="https://code.jquery.com/jquery-3.1.0.js"
      integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
      crossorigin="anonymous">
    </script>
    

    webpack.config.js

    externals: {
      jquery: 'jQuery'
    }
    

    This leaves any dependent modules unchanged, i.e. the code shown below will still work:

    import $ from 'jquery';
    
    $('.my-element').animate(...);