javascript - Why does webpack2's on-demand loading not take effect?
世界只因有你
世界只因有你 2017-05-19 10:26:20
0
4
768

I just started to get in touch with front-end modular development. I wrote a demo to learn webpack. I basically understand the configuration file and operation process, but on-demand loading always fails. Please help me:

In the entry file, three methods are used to load:

import test from './index/test.js';  
            
// const test=(resolve) => require(['./index/test.js'], resolve)
        
// const test=resolve => { require.ensure(['./index/test.js'], () => { resolve(require('./index/test.js')) }) }
    
test.exe('显示测试文字');//执行

The content of test.js is very simple, just print to the console:

const test={
    exe:function (res) {
        console.log('test方法的输出:'+res);
    }
};
export default test

All three methods have been tested. Only the first direct import method runs normally. The other two on-demand loading methods will report an error, indicating that the method cannot be found.
If test.exe('Display test text'); is commented out and only loaded but not executed, no error will be reported.
My understanding is that there is nothing wrong with loading the codes, but when they need to be loaded, they are not loaded successfully. Why is this? Did I write something wrong somewhere? Or do I need to make additional configuration to webpack.config.jx?

世界只因有你
世界只因有你

reply all(4)
淡淡烟草味

Give you an example for reference

html

<input class="btn" type="button" name="" value="load">

The js file plugin.js that needs to be loaded asynchronously

export default function Mod(name) {
  this.name = name;
}
Mod.prototype.hi = function() {
  console.log('Hi~ ' + this.name);
};

webpack’s entry compilation file entry.js

let demo = false;

let btn = document.querySelector('.btn');
btn.addEventListener('click', function() {//1、点击按钮btn时
   require.ensure([], function(require) {
      let mod = require('./bundles/plugin.js').default;//2、异步栽入plugin.js
      if (!demo) {
         demo = new mod('jackson'); //3、创建新实例并禁止多次重复创建
      }
      demo.hi();//4、触发该实例的方法
   }, 'mod1');//5、生成一个名字为mod1.js的异步chunk模块
});

The effect is that mod1.js is loaded and inserted into the head when clicked, but it is not loaded at the beginning

Finally, about the configuration of webpack.config.js.

   output: {
      path: path.resolve(__dirname, './dist'),
      filename: 'js/[name].js',
      publicPath: './dist/', 
      chunkFilename: 'js/async/[name].js'
      }

path + chunkFilename is the path generated by require.ensurei async module, but this is not the path that the html file refers to it

The real reference path is publicPath + chunkFilename, that is to say, if the html is in the project root directory, then the path where the html refers to this asynchronous js module is: ./dist/js/async/[name].js, but if your html In a folder, such as index/index.html, or the above path cannot be referenced, you need to change the publickPath to: '../dist/' and go outside the index folder to find this asynchronous module

迷茫

I have encountered a similar problem recently, let me briefly explain it.
When webpack is upgraded to 2, your second and third credit methods are not directly packaged into main.js.
That is to say, for modules that are required for first-screen loading, the asynchronous loading mode can no longer be used, but can be loaded on demand.
You can take a look in the packaged file. Except for the first method, your test method has not been packaged into your js.

Peter_Zhu

What do you want to do with the second and third writing methods? Do you want to simulate the writing method of AMD or CMD specifications?

The most common module specification is the ES6 module and the commonJS specification of node.js, because there are differences in specific loading details, such as loading time and different ways of referencing files. But the purpose of using webpack is to unify different specifications. Webpack will package all modules together in advance, give them an id respectively, and reference them by id, so that there is no difference between ES6 module and CommonJS specifications after webpack compiles. The same is true for AMD and CMD specifications.

If the poster wants to use webpack to implement delayed loading of CMD, this idea is wrong, because no matter which loading method, what webpack does is to package all the modules that you depend on (or will depend on) into one file, so that The corresponding package can be found by id at runtime, weakening the differences between specifications

为情所困

I don’t know your specific environment. My own environment has been upgraded to Webpack2 + React Router v4. You can refer to the documentation: https://reacttraining.cn/web/...

First you need to code and create a Bundle component to load the required modules and component files on demand.

import React, { Component } from 'react'

class Bundle extends Component {
  constructor(props){
    super(props)
    this.state = {
      mod: null
    }
  }
  componentWillMount() {
    this.load(this.props)
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }
  load(props) {
    this.setState({
      mod: null
    })
    props.load((mod) => {
      this.setState({
        // handle both es imports and cjs
        mod: mod.default ? mod.default : mod
      })
    })
  }
  render() {
    return this.props.children(this.state.mod)
  }
}

export default Bundle

The above code is copied from the document, and the state initialization method is modified. If you do not modify the state initialization method, you need to use babel-plugin-transform-class-properties.

There are three steps to use

  • ImportBundlemodule

import Bundle from './bundle.js';
  • Asynchronous loading

import loadHome  from 'bundle-loader?lazy!./components/Home';
  • Initialization

const Home = ({...props}) => (
  <Bundle load={loadHome}>
    {(Component) => Component? <Component {...props}/>: <p>Loading...</p>}
  </Bundle>
)

Of course, you still need to configure your .babelrcwebpack.config.js, I will give mine below, you can study it.

webpack.config.js

  module: {
    rules: [
      // Javascript模块加载器
      {
        test: /\.js|jsx$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory : true,
            presets: [
              ['es2015', {modules: false}]
            ],
            plugins: [
              'syntax-dynamic-import',
              'transform-async-to-generator',
              'transform-regenerator',
              'transform-runtime'
            ]
          }
        }
      },
      ...
    ]

.babelrc

{
  "presets": [
    "es2017",
    [
      "latest",
      {"es2015":{"modules": false}}
    ],
    "stage-0",
    "react"
  ],
  "plugins": [
    ["import",{"libraryName": "antd","style": true }],
    "react-hot-loader/babel"
  ]
}

There is also the configuration of the public block output plugin

  plugins: [
    ...
    new webpack.optimize.CommonsChunkPlugin({
      name: ["vendor", "manifest"],
      filename: '[name].[hash].js',
      minChunks: 2
    }),
    ...
  ]

After passing the above N steps, the component Home can be used.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template