javascript - Warum wird das On-Demand-Laden von WebPack2 nicht wirksam?
世界只因有你
世界只因有你 2017-05-19 10:26:20
0
4
753

Ich habe gerade angefangen, mit der modularen Front-End-Entwicklung in Kontakt zu treten, um die Konfigurationsdatei und den Betriebsprozess zu erlernen, aber das Laden auf Abruf schlägt immer fehl:

In der Eintragsdatei werden 3 Methoden zum Laden verwendet:

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('显示测试文字');//执行

Der Inhalt von test.js ist sehr einfach, drucken Sie ihn einfach auf der Konsole aus:

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

Drei Methoden wurden getestet. Nur die erste Direktimportmethode wird normal ausgeführt. Die anderen beiden On-Demand-Lademethoden melden einen Fehler und weisen darauf hin, dass die Methode nicht gefunden werden kann.
Wenn Sie auskommentieren test.exe('显示测试文字'); und nur laden, aber nicht ausführen, wird kein Fehler gemeldet.
Nach meinem Verständnis ist das Laden der Codes in Ordnung, aber wenn sie geladen werden müssen, werden sie nicht erfolgreich geladen. Warum ist das so? Habe ich irgendwo etwas falsch geschrieben? Oder muss ich eine zusätzliche Konfiguration an webpack.config.jx vornehmen?

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

Antworte allen(4)
淡淡烟草味

给你个实例参考下

html

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

需要异步加载的js文件 plugin.js

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

webpack的入口编译文件 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模块
});

效果就是点击时,mod1.js才加载插入head,一开始是不加载的

最后关于webpack.config.js的配置。

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

path + chunkFilename是require.ensurei异步模块生成的路径,但这不是html文件引用它的路径

真正的引用路径是publicPath + chunkFilename,也就是说如果html在项目根目录,那么html引用这个异步js模块的路径就是:./dist/js/async/[name].js,但是如果你的html在一个文件夹里,比如是index/index.html,要么上面的路径是不可能引用到的,需要改publickPath为:'../dist/'到index文件夹外面去找这个异步模块

迷茫

最近也碰到了类似的问题,大致说一下。
webpack升级到2的时候对你第二种和第三种的信用方式,都没有直接打包到main.js里面。
也就是说对于首屏加载就需要的模块,不能再使用异步加载的模式,按需加载的可以。
你可以去打包出来的文件里面看一下,你的除了第一种方式,test方法都没有被打包到你的js里面。

Peter_Zhu

第二个和第三种写法想做什么?是想模拟 AMD 或者 CMD 规范的写法么?

最常见 module 规范 ES6 module 和 node.js 的 commonJS 规范,因为在具体加载细节上有出入,比如加载时间和对文件的引用方式的不同。但是使用webpack的目的就是将不同规范统一化,webpack 会提前将所有 module
打包在一起,分别给一个 id ,通过 id 进行引用,使得 ES6 module 和 CommonJS 规范在 webpack 编译后没有任何区别,同样对于 AMD 和 CMD 规范。

如果楼主想用 webpack 实现 CMD 的延迟加载这个思路就是错的,因为无论哪种加载方式,webpack 所做的,就是将你的依赖(或者说即将依赖)的所有模块打包进一个文件,以至于在运行时都能通过 id 找到对应的包,弱化规范间的差异

为情所困

不知道你的具体环境, 我自己的环境现状已经升级到Webpack2 + React Router v4. 可以参考文档: https://reacttraining.cn/web/...

首先需要编码, 创建一个 Bundle 组件, 用于按需加载需要的模块, 组件文件.

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

上述代码是从文档里面抄的, 修改了状态的初始化方式, 如果不修改状态的初始化方式, 就需要用到babel-plugin-transform-class-properties.

使用的时候包含三个个步骤

  • 导入Bundle模块

import Bundle from './bundle.js';
  • 异步加载

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

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

当然, 你还需要配置你的 .babelrcwebpack.config.js, 下面我给我我自己的, 你可以研究一下.

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"
  ]
}

还有公共块输出插件的配置

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

通过上述N个步骤后, 组件Home就可以使用了.

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage