方案一
webpack-demo|- package.json|- webpack.common.js|- webpack.dev.js|- webpack.prod.js|- server.js|- DEV-server.js|- /dist|- /src|- data.xml|- icon.png+|- style.css|- my-font.woff|- my-font.woff2|- print.js|- index.js|- math.js|- /node_modules
// index.jsimport _ from 'lodash';import './style.css';import Icon from './icon.svg';import Data from './data.xml';import printMe from './print.js';import { cube } from './math.js';function componentPre() {let element = document.createElement('pre');element.innerHTML = ['Hello webpack!','5 cubed is equal to ' + cube(5)].join('\n\n');element.classList.add('hello');var myIcon = new Image();myIcon.src = Icon;element.appendChild(myIcon);var btn = document.createElement('button');btn.innerHTML = 'Click me and check the console!';btn.onclick = printMe;element.appendChild(btn);console.log(Data);return element;}function component() {let element = document.createElement('div');element.innerHTML = _.join(['Hello', 'webpack'], ' ');element.classList.add('hello');var myIcon = new Image();myIcon.src = Icon;element.appendChild(myIcon);var btn = document.createElement('button');btn.innerHTML = 'Click me and check the console!';btn.onclick = printMe;element.appendChild(btn);console.log(Data);return element;}// document.body.appendChild(component());let element = componentPre(); // Store the element to re-render on print.js changesdocument.body.appendChild(element);if (module.hot) {module.hot.accept('./print.js', function () {console.log('Accepting the updated printMe module!');document.body.removeChild(element);element = componentPre(); // Re-render the "component" to update the click handlerdocument.body.appendChild(element);})}
// print.jsimport _ from 'lodash';export default function printMe() {// console.log('I get called from print.js!');console.log('Updating print.js...' + _.join(['Another', 'module', 'loaded!'], ' '));}
// webpack.common.jsconst path = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成页面const CleanWebpackPlugin = require('clean-webpack-plugin'); // 自动清理,清理dist旧文件const webpack = require('webpack');module.exports = {entry: {app: './src/index.js',print: './src/print.js',},optimization: { // 防止重复splitChunks: {chunks: 'all'}},plugins: [new CleanWebpackPlugin(['dist']),new HtmlWebpackPlugin({title: 'Output Management'}),new webpack.HotModuleReplacementPlugin()],output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),publicPath: '/'},module: {rules: [{test: /\.css$/,use: ['style-loader','css-loader']},{test: /\.(png|svg|jpg|gif)$/,use: ['file-loader']},{test: /\.(woff|woff2|eot|ttf|otf)$/,use: ['file-loader']},{test: /\.(csv|tsv)$/,use: ['csv-loader']},{test: /\.xml$/,use: ['xml-loader']}],}};
有了optimization.splitChunks配置选项,我们现在应该看到从我们的index.bundle.js和中删除了重复的依赖项print.bundle.js。该插件应该注意到我们已经分离lodash出一个单独的块并从我们的主捆绑中移除了自重
以下是社区提供的用于拆分代码的一些其他有用的插件和加载器:
mini-css-extract-plugin:用于从主应用程序中分离CSS。
bundle-loader:用于拆分代码并延迟加载生成的包。
promise-loader:类似
bundle-loader但使用承诺。
方案二
在动态代码拆分方面,webpack支持两种类似的技术。第一种建议的方法是使用符合ECMAScript提议的import()语法进行动态导入。传统的,特定于webpack的方法是使用。让我们尝试使用这两种方法中的第一种……
import()调用内部使用promises。如果您使用import()较旧的浏览器,请记住使用填充程序来填充,Promise例如es6-promise或promise- polyfill。
// webpack.common.jsconst path = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成页面const CleanWebpackPlugin = require('clean-webpack-plugin'); // 自动清理,清理dist旧文件const webpack = require('webpack');module.exports = {entry: {app: './src/index.js',// print: './src/print.js',},// optimization: { // 防止重复// splitChunks: {// chunks: 'all'// }// },plugins: [new CleanWebpackPlugin(['dist']),new HtmlWebpackPlugin({title: 'Output Management'}),new webpack.HotModuleReplacementPlugin()],output: {filename: '[name].bundle.js',// ==================================================================chunkFilename: '[name].bundle.js', // 使用这个// ==================================================================path: path.resolve(__dirname, 'dist'),publicPath: '/'},module: {rules: [{test: /\.css$/,use: ['style-loader','css-loader']},{test: /\.(png|svg|jpg|gif)$/,use: ['file-loader']},{test: /\.(woff|woff2|eot|ttf|otf)$/,use: ['file-loader']},{test: /\.(csv|tsv)$/,use: ['csv-loader']},{test: /\.xml$/,use: ['xml-loader']}],}};
下面代码需要注意的是 import printMe from ‘./print.js’; 如果你的引入依赖将包含你所想要拆分的文件时,此文件不被拆分。并且前一个文件加载过后,import(/ webpackChunkName: “lodash” / ‘lodash’),’./print.js文件不需要引入,直接使用即可。
// index.js// import _ from 'lodash';import './style.css';import Icon from './icon.svg';import Data from './data.xml';// import printMe from './print.js';import { cube } from './math.js';function getComponent() {return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {var element = document.createElement('div');element.innerHTML = _.join(['Hello', 'webpack'], ' ');return element;}).catch(error => 'An error occurred while loading the component');}getComponent().then(component => {document.body.appendChild(component);})
作为import()返回承诺,它可以与async函数一起使用。但是,这需要使用像Babel这样的预处理器和Syntax Dynamic Import Babel插件。以下是如何简化代码:
async function getComponent() {var element = document.createElement('div');const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash');element.innerHTML = _.join(['Hello', 'webpack'], ' ');return element;}getComponent().then(component => {document.body.appendChild(component);});
