webpack: Webpack does not create a split point by import() in webpack 4, unlike of require.ensure in webpack 2, 3

Bug report

I have an app, where I split my code on chunks by they routes matches. In webpack 2, 3 it makes by require.ensure perfectly, but for now, in Webpack 4 it does not create a split point and does not embed an async module loader (jsonp) when bundling in dev or prod mode for all chunks. Instead of it - webpack 4 just compose all chunks in one common app.js chunk that is not good…

What is the current behavior? Webpack creates a single app.js bundle, instead of separate app routes bundles, just like: app.js, appFirstChunk.js, appSecondChunk.js, etc…

If the current behavior is a bug, please provide the steps to reproduce. I just rewrite my require.ensure way of code splitting on new in webpack 4 - import() syntax as said in this documentation https://webpack.js.org/guides/code-splitting/ and got a problem with bundles creation.

My component spit point (rewrited from require.ensure to import() syntax) :

import { injectReducer } from '../../store/rootReducer'
import { injectSaga, cancelTask } from '../../store/middleware/saga'
import { fetchData } from './modules/actions'
import { typeID } from './constants'

import appFirstChunk from './containers/appFirstChunk'
import reducer from './modules/reducers'
import saga from './modules/saga'

export default store => ({
  path: '/app_first_chunk',
  /*  Async getComponent is only invoked when route matches   */
  getComponent(nextState, cb) {

    /* New import() syntax for code splitting in webpack 4 */
    return import('./containers/appFirstChunk')
      .then(() => injectReducer(store, { key: 'app_first_chunk', reducer }))
      .then(() => injectSaga({ key: 'app_first_chunk', saga }))
      .then(() => cb(null, appFirstChunk))
      .then(() => store.dispatch(fetchData('&step=appFirstChunk&typeID=' + typeID)))
      .then(() => 'app_first_chunk')
      .catch(error => console.log(error))

    /*  Webpack 2, 3 - use 'require.ensure' to create a split point
        and embed an async module loader (jsonp) when bundling   */
    // require.ensure(
    //   [],
    //   require => {
    //     /*  Webpack - use require callback to define
    //       dependencies for bundling   */
    //     const appFirstChunk = require('./containers/appFirstChunk').default
    //     const reducer = require('./modules/reducers').default
    //     const saga = require('./modules/saga').default

    //     /*  Add the reducer to the store on key 'app_first_chunk'  */
    //     injectReducer(store, { key: 'app_first_chunk', reducer })

    //     /*  Add the saga to the store on key 'app_first_chunk'  */
    //     injectSaga({ key: 'app_first_chunk', saga })

    //     /*  Return getComponent   */
    //     cb(null, appFirstChunk)

    //     /* load initial crime data  */
    //     store.dispatch(fetchData('&step=appFirstChunk&typeID=' + typeID))

    //     /* Webpack named bundle   */
    //   },
    //   'app_first_chunk'
    // )
  }
})

What is the expected behavior? Webpack must create a split points for appFirstChunk bundle creation by import() in webpack 4, like of require.ensure do this in webpack 2, 3. Instead of it embed my component code into the common app.js bundle.

Other relevant information: my webpackConfig on gist https://gist.github.com/BiosBoy/d970d8eb965b3a97cdb0e1bc5d869f43 Windows 10 NodeJs 6.0.1 Yarn 1.7.0 Webpack 4.14.0 html-webpack-plugin 3.2.0

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (6 by maintainers)

Most upvoted comments

@NallaRK Hi, catch it:

export default store => ({
  path: '/component',
  /*  Async getComponent is only invoked when route matches   */
  getComponent(nextState, cb) {
    return (
      import(/* webpackChunkName: "component" */ './containers/Component')
        .then(({ default: Component }) => {
          /*  Add the reducer to the store on key 'component'  */
          injectReducer(store, { key: 'component', reducer })
          return Component
        })
        .then(Component => {
          /*  Add the saga to the store on key 'component'  */
          injectSaga({ key: 'component', saga })
          return Component
        })
        .then(Component => cb(null, Component))
        .then(() => doSomething())
        .catch(error => console.log(error))
    )
  },
  onLeave() {
    console.log('onLeave')
  }
})

@BiosBoy, I believe the uglify: true option to babel-preset-env forces all transforms (effectively undoing the module: false), which presumably means babel converts the import() before webpack even gets to see it: https://github.com/babel/babel-preset-env#targetsuglify

webpack 4 now uses uglify-es by default, so making babel compile down to ES5 is no longer required.

This may not be a 100% correct but the translation is roughly:

// Old require.ensure:
// require.ensure([], require => {
//     useComponent(require('./containers/Component').default)
// }, 'Component')

// New dynamic import
import(/* webpackChunkName: "component" */ './containers/Component')
    .then(({ default: Component }) => useComponent(Component))
    .catch(console.error)

I think you can solve this on your own. It’s not a webpack problem.