一, 按需加载
1.1, 为什么需要按需加载
随着 web 应用功能越来越复杂, 模块打包后体积越来越大, 这样会带来两个问题:
所有的 JS 文件打包到一个 bundle.JS 中导致首屏加载时间过长
有时我们只是修改了一个模块就得重新打包所用的文件 webpack 天然支持多种模块系统风格, 支持灵活的代码分割
1.2, 按需加载的三种方式
webpack 支持三种代码分割方式分别是:
- AMD: require(url, '别名')
- CommonJS: require.ensure([],func),
- ES6: import(url)
1.3,vue 中如何按需加载
对应的 vue 中也有三种对应的解决方式:
vue 异步组件技术
- import Vue from 'vue'
- import Router from 'vue-router'
- Vue.use(Router)
- export default new Router({
- mode: 'history',
- routes: [
- {
- path: '/vue-async',
- name: 'vueAsync',
- component: resolve => require(['@/components/VueAsync'], resolve)
- }
- ]
- })
webpack 提供的 require.ensure()
- import Vue from 'vue'
- import Router from 'vue-router'
- Vue.use(Router)
- export default new Router({
- mode: 'history',
- routes: [
- {
- path: '/require-ensure'
- name: 'RequireEnsure',
- component: r => require.ensure([], () => r(require('@/components/RequireEnsure'), 'ensure'))
- }
- ]
- })
利用 ES6 提案的 import()函数
- import Vue from 'vue'
- import Router from 'vue-router'
- const EsImport = () => import('@/components/EsImport')
- Vue.use(Router)
- export default new Router({
- mode: 'history',
- routes: [
- {
- path: '/es-import',
- name: 'EsImport',
- component: EsImport
- }
- ]
- })
第三种方式比较简单, 而且代码组织也比较明显, 所以也更常被使用
二, 合理使用 commonsChunkPlugin
2.1, 为什么使用 commonsChunkPlugin
CommonsChunkPlugin 插件, 是一个可选的用于建立一个独立文件 (又称作 chunk) 的功能, 这个文件包括多个入口 chunk 的公共模块. 简单来说 CommonsChunkPlugin 主要是用来提取第三方库和公共模块, 避免首屏加载的 bundle 文件或者按需加载的 bundle 文件体积过大, 从而导致加载时间过长, 着实是优化的一把利器.
2.2,commonsPlugin 的集中使用场景
提取两个及两个以上 Chunk 的公共代码
将 Code Split 切割出来的 Chunk「就是子 Chunk」, 提取到父 Chunk
将 Code Split 切割出来的 Chunk, 提取到一个新的异步加载的 Chunk
提取某个类似 jQuery 或 react 的代码库「但是这个用得很少, 使用用 dll 插件来打包会更好一些, 一下篇介绍」
三, 使用 DllPlugin 和 DllReferencePlugin 来提高打包速度
3.1, 为什么使用 DllPlugin 和 DllReferencePlugin
使用 CommonsChunkPlugin, 设置 minChunks 为 Infinity 可用于打包此类代码, 但缺点也是比较明显的:
每次执行 webpack 时, 都会去解析打包这些代码, 耗时也耗资源
如果设置了文件名 hash, 一次构建生成一个新的 hash, 那这些文件即使没有变, 文件名也会变, 不利于缓存. 对于这些代码我是用 Dll 插件单独构建.
3.2,vue-cli 中如何利用 DllPlugin 和 DllReferencePlugin
在 build 目录下编写 webpack.dll.conf.JS
- const path = require('path')
- const webpack = require('webpack')
- const AssetsPlugin = require('assets-webpack-plugin')
- const CleanWebpackPlugin = require('clean-webpack-plugin')
- module.exports = {
- entry: {
- libs: [
- 'vue/dist/vue.esm.js',
- 'vue-router',
- 'vuex',
- 'element-ui'
- ]
- },
- output: {
- path: path.resolve(__dirname, '../static'),
- filename: '[name].[chunkhash:7].js',
- library: '[name]_library'
- },
- plugins: [
- new webpack.DllPlugin({
- path: path.resolve(__dirname, '../static/[name]-manifest.json'),
- name: '[name]_library',
- context: __dirname
- }),
- new webpack.optimize.UglifyJsPlugin({
- compress: {
- warnings: false
- }
- }),
- new AssetsPlugin({
- filename: 'bundle-config.json',
- path: './static'
- }),
- new CleanWebpackPlugin(['static'], {
- root: path.join(__dirname, '../'),
- verbose: true,
- dry: false
- })
- ]
- }
在 build 目录下编写 buildDll.JS
- const path = require('path')
- const webpack = require('webpack')
- const webpackDll = require('./webpack.dll.conf')
- const chalk = require('chalk')
- const ora = require('ora')
- const rm = require('rimraf')
- const spinner = ora({
- color: 'green',
- text: 'Dll 生产中'
- })
- spinner.start()
- rm(path.resolve(__dirname, '../static'), err => {
- if(err) throw err
- webpack(webpackDll, (err, status) => {
- spinner.stop()
- if(err) throw err
- process.stdout.write(status.toString({
- colors: true,
- modules: false,
- children: false,
- chunks: false,
- chunkModules: false
- }) + '\n\n')
- })
- console.log(chalk.cyan('dll success'))
- })
修改 webpack.base.conf.JS
- // 添加 plugins
- plugins: [
- new webpack.DllReferencePlugin({
- context: __dirname,
- manifest: require('../static/libs-manifest.json')
- })
- ]
修改 webpack.dev.conf.JS
- const bundleConfig = require("../static/bundle-config.json")// 调入生成的的路径 JSON
- new htmlWebpackPlugin({
- filename: 'index.html',
- template: 'index.html',
- inject: true,
- libJsName: bundleConfig.libs.JS
- }),
修改 webpack.prod.conf.JS
- const bundleConfig = require("../static/bundle-config.json")// 调入生成的的路径 JSON
- new HtmlWebpackPlugin({
... 省略号...
libJsName: bundleConfig.libs.JS
... 省略号...
})
修改 index.HTML
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
- <title>
- vue-multipage
- </title>
- </head>
- <body>
- <div id="app">
- </div>
- <!-- built files will be auto injected -->
- <script src="./static/<%= htmlWebpackPlugin.options.libJsName %>">
- </script>
- </body>
- </HTML>
参考文章:
为什么要 Webpack https://segmentfault.com/a/1190000007498296
webpack 代码分割技巧 http://foio.github.io/wepack-code-spliting/
vue-cli,webpack 提取第三方库 -----DllPlugin,DllReferencePlugin https://www.cnblogs.com/cag2050/p/7264744.html
来源: https://juejin.im/post/5c3c55aa51882524b4073394