0

I ran into a problem using code splitting and the CommonsChunkPlugin. I'm used to require.js where the files are cached automatically. I'm also using the libraryTarget: 'amd' for my webpack configuration.

Considering these two simple files, this is the output I get:

// fileA.js
import $ from 'jquery'

// fileB.js
import $ from 'jquery'

   Asset    Size  Chunks                    Chunk Names
fileB.js  271 kB       0  [emitted]  [big]  fileB
fileA.js  271 kB       1  [emitted]  [big]  fileA

So both files, fileA and fileB have jquery included. Also, I'm able to use these files like this in my html file.

require(['./dist/fileA.js', './dist/fileB.js'], function () {
})

As per the docs I can use the CommonsChunkPlugin to basically extract jquery into its own file, so my config looks like this:

new webpack.optimize.CommonsChunkPlugin({
  name: 'common'
}),

resulting in this output:

    Asset       Size  Chunks                    Chunk Names
 fileB.js  635 bytes       0  [emitted]         fileB
 fileA.js  617 bytes       1  [emitted]         fileA
common.js     274 kB       2  [emitted]  [big]  common

BUT now I'm unable to use the above require block, because the common.js also includes the webpack runtime. All I now get is an Uncaught ReferenceError: webpackJsonp is not defined error.

So what I would need is:

  1. fileA.js (only contains "fileA" code, requiring jquery)
  2. fileB.js (only contains "fileB" code, requiring jquery)
  3. jquery.js (all of the jquery stuff)
  4. common.js (only contains the runtime for webpack)

I already tried something like this for fileA and fileB, but it's basically the same output:

define(['jquery'], function ($) {

})

A (Vendor) library should only be loaded, if a script (like fileA) is loaded and has it as a dependency (as it is with requirejs).

Can this be accomplished? I skimmed through the webpack2 docs numerous times, but couldn't find anything that could help me...

edit: Ok, with the help of some github issues, I managed to get the correct asset generation with the following configuration:

module.exports = {
  entry: {
    jquery: ['jquery'],
    vue: ['vue'],
    fileA: ['./src/fileA.js'],
    fileB: ['./src/fileB.js'],
    fileC: ['./src/fileC.js']
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist',
    filename: '[name].js',
    libraryTarget: 'amd'
  }
}

module.exports.plugins = (module.exports.plugins || []).concat([
  new webpack.optimize.CommonsChunkPlugin({
    name: ['vue', 'jquery']
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'common',
    chunks: ['vue', 'jquery'],
    minChunks: Infinity
  }),
  new webpack.optimize.OccurrenceOrderPlugin()
])

I changed the source files to:

// fileA.js
import $ from 'jquery'
import Vue from 'vue'
// fileB.js
import $ from 'jquery'
// fileC.js
import Vue from 'vue'

And this is the output:

   vue.js     193 kB       0  [emitted]         vue
 fileC.js  447 bytes       1  [emitted]         fileC
 fileB.js  579 bytes       2  [emitted]         fileB
 fileA.js  666 bytes       3  [emitted]         fileA
jquery.js     269 kB       4  [emitted]  [big]  jquery
common.js    5.78 kB       5  [emitted]         common

However, using it in an .html file like so results in the following error:

<body>
  <script src="./dist/common.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.js"></script>
  <script>
    require(['./dist/fileA.js', './dist/fileB.js', './dist/fileC.js'], function (a, b, c) {
    })
  </script>
</body>

The following error occurs both for fileA and for fileC...

common.js:55 Uncaught TypeError: Cannot read property 'call' of undefined
    at __webpack_require__ (common.js:55)
    at Object.7 (fileA.js:16)
    at __webpack_require__ (common.js:55)
    at Object.6 (fileA.js:6)
    at __webpack_require__ (common.js:55)
    at webpackJsonpCallback (common.js:26)
    at fileA.js:1
    at Object.execCb (require.js:1696)
    at Module.check (require.js:883)
    at Module.enable (require.js:1176)

edit:

I've create a repo on github showing the problem I ran into. As per the answer of Rafael De Leon, I'm now using System.import('<module>') to asynchronously import other files. main.ts imports fileA.ts via this syntax, resulting in an error when output.js (the compiled main.ts file) is required. The error seems to happen when fileA is being loaded from withing output.js... I've also created a github issue, because I think it's a bug.

Johannes
  • 1,249
  • 3
  • 17
  • 33

1 Answers1

0

A (Vendor) library should only be loaded, if a script (like fileA) is loaded and has it as a dependency (as it is with requirejs).

If you want this result, CommonsChunkPlugin isn't what you are looking for. That plugin is to aggregate files that are used by different entries or other CommonChunkPlugin into one file.

I think what you are looking for import() or require.ensure to load "vendor" files on demand

otherwise How to bundle vendor scripts separately and require them as needed with Webpack? will work

Rafael De Leon
  • 1,580
  • 1
  • 12
  • 11
  • I already took a look at `import()` and `require.ensure` and couldn't get it work properly. I will try the suggested question however and come back to you asap! – Johannes Jul 04 '17 at 20:45
  • I updated my answer based on your proposal, but ran into another problem. Any ideas? – Johannes Jul 14 '17 at 19:16