Lazy-load only unloaded-chunk is different from webpack

I am using require.ensure

to create chunks that are lazy loaded by route in Angular SPA. I am not using any special lazy loading plugin for Angular, just allowing ui-router.

Part 2 requires content # 1. For example:

require.ensure([], function(require) {
   require('shop/shop');         // Creates chunk 1
}, 'Shop');

require.ensure([], function(require) {
   require('signup/signup');      // Creates chunk 2
}, 'Signup');

// signup/signup.js
define([
  '_auth.scss',
  'shop/shop'                    // Chunk 2 depends on chunk 1
], function() { });

      

My output from webpack looks something like this:

Asset -------- Chunk

app.js ------- 0

1.Shop.js ---------- 1

2.Signup.js ---------- 1,2

If I move from {1,2} โ†’ {1}, I don't make requests because {1} is satisfied by {1,2}. But if I go {1} -> {1,2}, I get all {1,2}, not just the chunk containing {2}.

Is there a way that I can only get the "unloaded chunk diff" from a chunk using Webpack?

I tried to use CommonsChunkPlugin this way: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk

new webpack.optimize.CommonsChunkPlugin({
   name: 'main',
   async: true
})

      

But if I use "main" then somehow I end up with a giant final package / chunk that's bigger than even my entry point, which contains most of the vendor code.

If this is not currently supported by Webpack, would it be reasonable to assume that one could write a plugin that generates files for possible valid "unloaded chunks" permutations and then loads the correct one at runtime?

Thank you for understanding!

My webpack.config.js:

var webpack = require('webpack');
var path = require('path');

process.env.UV_THREADPOOL_SIZE = 100;

var alias = {
  json3: 'json3/lib/json3',
  es5shim: 'es5-shim/es5-shim',
  angular: 'angular/angular',
  lodash: 'lodash/lodash',
  angularRoute: 'angular-ui-router/release/angular-ui-router',
  angularAnimate: 'angular-animate/angular-animate',
  moment: 'moment/moment',
  'angular-moment': 'angular-moment/angular-moment',
  'angular-cookies':  'angular-cookies/angular-cookies',
  'angular-encode-uri': 'angular-encode-uri/dist/angular-encode-uri',
  'angulartics-gtm': __dirname + '/app/vendor/angulartics/src/angulartics-gtm',
  angulartics: __dirname + '/app/vendor/angulartics/src/angulartics'
};

module.exports = {
  context: __dirname + '/app/scripts',
  entry: {
    app: 'bootstrap.js'
  },
  output: {
    path: __dirname + '/dist/scripts',
    filename: '[name].js',
    publicPath: '/scripts/'
  },
  plugins: [
    new webpack.ProvidePlugin({
      _: 'lodash'
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.ContextReplacementPlugin(
      /moment[\/\\]locale$/,
      /be|de\-at|de|en\-gb|es|fr|it|nl|pl|pt|pt\-br|ru|sv/
    )
  ],
  module: {
    loaders: [
      { test: /[\/]angular\.js$/, loader: 'exports?angular' },
      { test: /\.html$/, loader: 'html', include: __dirname + '/app/scripts' },
      { test: /\.scss$/, loader: 'style!css!sass', include: __dirname + '/app/styles/sass' },
      { test: /\.css$/, loader: 'style!css' },
      { test: /angular\-moment/, loader: 'imports?define=>false&angular&moment'},
      {
        test: /images\/.*\.svg$/i,
        loaders: [
            'file?name=[path][name].[ext]',
            'image-webpack?bypassOnDebug'
        ]
      }
    ]
  },
  resolve: {
    extensions: ['', '.js', '.html', '.scss', '.css', '.svg'],
    root: [ __dirname + '/app' ],
    modulesDirectories: [
      'vendor',
      'scripts',
      'styles/sass',
      'icons'
    ],
    alias: alias
  },
  noParse: Object.keys(alias),
  devtool: 'cheap-source-map'
};

      

+3


source to share


1 answer


There is currently no way to do this with webpack automatically, but this is an idea for a manual way:

Completely untested and quite hacky, but it might solve your problem for this special case.



// chunk 1 loading (as before)

require.ensure([], function(require) {
   require('shop/shop');         // Creates chunk 1
}, 'Shop');

// chunk 2 loading:

// check if shop already loaded
if(require.resolveWeak("shop/shop") in __webpack_modules__) { 

  // the first require.ensure maps to chunk 1 but doesn't load anything
  // because it already loaded
  require.ensure(['shop/shop'], function(require) {
    // the second require.ensure creates a child chunk and the optimization
    // removes all modules which are already in chunk 1
    require.ensure([], function(require) {
      require('signup/signup');      // Creates chunk 3 = 2 minus 1
    }, 'Signup2'); // important: other name (or no name)
  }, 'Shop');

} else {

  // full chunk load
  require.ensure([], function(require) {
    require('signup/signup');      // Creates chunk 2
  }, 'Signup');

}

      

+1


source







All Articles