来自 美高梅4858永利777 2019-12-21 21:40 的文章
当前位置: 美高梅游戏平台网站 > 美高梅4858永利777 > 正文

webpack4.0打包优化策略整理小结_javascript技巧_脚本之家

 resolve: { mainFields: ["main"], alias: { 'react': path.resolve(__dirname, './node_modules/react/cjs/react.production.min.js') } }

6.ParallelUglifyPlugin

webpack会从入口触发,将所有的依赖项放到一个list里边,然后每次修改文件内容,回去遍历整个list里边的文件,看是否有编辑时间的变化,如果有的话则进行编译

3.module.noParse

使用动态链接库预编译大模块

1.静态解析 es6模块时 编译时加载 即在解析阶段就确定输出的模块的依赖关系,所以es6模块的import一般写在被引入文件的开头

module.exports = { resolve: { // 指定当前目录下的node_modules目录 modules: [path.resolve(__dirname, 'node_modules')] }}
npm i happypack@next -D

新建一个文件webpack_dll.config.js,内容如下

webapck4 新特性介绍-参考资料

简介

在一个动态链接库中可以包含其他模块调用的函数和数据,动态链接库只需被编译一次,在之后的构建过程中被动态链接库包含的模块将不会被重新编译,而是直接使用动态链接库中的代码。

多进程压缩文件

// .babelrc{ "presets": [ [ "env", { modules: false // 不要编译ES6模块 }, "react", "stage-0" ] ]}

减少监听文件

const HappyPack = require;const os = require; // node 提供的系统操作模块 // 根据我的系统的内核数量 指定线程池个数 也可以其他数量const happyThreadPool = HappyPack.ThreadPool.lenght})module: { rules: [ { test: /.js$/, use: 'happypack/loader?id=babel', exclude: /node_modules/, include: path.resolve } ]},plugins: [ new HappyPack({ // 基础参数设置 id: 'babel', // 上面loader?后面指定的id loaders: ['babel-loader?cacheDirectory'], // 实际匹配处理的loader threadPool: happyThreadPool, // cache: true // 已被弃用 verbose: true });]

补充4-HappyPack原理

2.2 resolve.alias 配置路径别名

执行webpack --config webpack_dll.config.js进行首次编译

module: { rules: [ { test: /.js$/, use: 'babel-loader?cacheDirectory', // 缓存loader执行结果 发现打包速度已经明显提升了 exclude: /node_modules/, include: path.resolve } ]}

看了下react和lodash,只有一个main,目前来看使用es6看来还不普遍,所以这个值目前可能不太重要

cnpm i webpack-parallel-uglify-plugin -D

// webpck.config.jsconst ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');plugins: [ new ParallelUglifyPlugin({ workerCount: 4, uglifyJS: { output: { beautify: false, // 不需要格式化 comments: false // 保留注释 }, compress: { // 压缩 warnings: false, // 删除无用代码时不输出警告 drop_console: true, // 删除console语句 collapse_vars: true, // 内嵌定义了但是只有用到一次的变量 reduce_vars: true // 提取出出现多次但是没有定义成变量去引用的静态值 } } });]

webpack --mode production

读了《深入浅出webpack》总结一下常用的webpack的构建优化策略,可通过以下手段来提升项目构建时的速度

// main.jsimport dep1 from 'util/dep1';import add from 'util/add';
const path = require;const webpack = require;// 复用的大模块放在这里,这样每次都不需要重新编译了const vendors = [ 'react', 'react-dom', 'lodash'];module.exports = { mode: 'development', output: { path: path.resolve, filename: '[name].js', library: '[name]', }, entry: { vendors, }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, './dist/manifest.json'), name: '[name]', }), ],};
alias: { util$: resolve}

import Test1 from 'util'; // 精确匹配,所以 src/util/add.js 被解析和导入import Test2 from 'util/dep1.js'; // 精确匹配,触发普通解析 util/dep1.js

补充

5.2 在主配置文件中使用动态链接库文件

更精准的查找目录

通过排除node_modules下的文件 从而缩小了loader加载搜索范围 高概率命中文件

使用动态链接库,提前编译大模块

当引入模块时不带文件后缀 webpack会根据此配置自动解析确定的文件后缀

 rules: [{ // 正则尽量准确 test: /.js$/, // 使用缓存,缓存后在文件未改变时编译会更快 use: ['babel-loader?cacheDirectory'], // 指定需要处理的目录 include: path.resolve // 理论上只有include就够了,但是某些情况需要排除文件的时候可以用这个,排除不需要处理文件 // exclude: [] }]

5.1 定义DLL配置

module.export = { watchOptions: { ignored: /node_modules/ }}

5.1.1 创建一个DLL配置文件webpack_dll.config.js

平时写代码,我们都习惯直接写文件名,而不去写扩展名,那么解析则按照下面属性进行解析

将web应用依赖的基础模块抽离出来,打包到单独的动态链接库中。一个链接库可以包含多个模块。 当需要导入的模块存在于动态链接库,模块不会再次打包,而是去动态链接库中去获取。 页面依赖的所有动态链接库都需要被加载。

默认的这个值查找方式见官网点击此处

例如,一些位于 src/ 文件夹下的常用模块:

补充3-动态链接库思想

module.exports = { entry: { react: ['react', 'react-dom'] }, output: { filename: '[name].dll.js', // 动态链接库输出的文件名称 path: path.join, // 动态链接库输出路径 libraryTarget: 'var', // 链接库输出方式 默认'var'形式赋给变量 b library: '_dll_[name]_[hash]' // 全局变量名称 导出库将被以var的形式赋给这个全局变量 通过这个变量获取到里面模块 }, plugins: [ new webpack.DllPlugin({ // path 指定manifest文件的输出路径 path: path.join(__dirname, 'dist', '[name].manifest.json'), name: '_dll_[name]_[hash]', // 和library 一致,输出的manifest.json中的name值 }) ]}
module.exports = { resolve: { mainFields: ['main'] }}

html-webpack-include-assets-plugin 将js css资源添加到html中 扩展html插件的功能

多进程处理文件

webpack --config webpack_dll.config.js --mode production

将loader规则写清楚

配置webpack.config.js

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

const webpack = require;const HtmlWebpackPlugin = require('html-webpack-plugin');const HtmlIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');pluings: [ new webpack.DllReferencePlugin({ manifest: require('./dist/react.manifest.json') }), new HtmlWebpackPlugin({ template: path.join(__dirname, 'src/index.html') }), new HtmlIncludeAssetsPlugin({ assets: ['./react.dll.js'], // 添加的资源相对html的路径 append: false // false 在其他资源的之前添加 true 在其他资源之后添加 });]

向要开发的网页中注入代理客户端代码,通过代理客户端去刷新整个页面 将要开发的网页放进一个iframe,通过刷新iframe去看刷新效果

// webpack.config.jsconst webpack = require;plugins: [ // 当我们需要使用动态链接库时 首先会找到manifest文件 得到name值记录的全局变量名称 然后找到动态链接库文件 进行加载 new webpack.DllReferencePlugin({ manifest: require('./dist/react.manifest.json') })]

其他没那么重要的优化

commonJS模块:

使用ParallelUglifyPlugin多进程同时压缩文件

7.1 保留ES6模块化语法

当有设置cacheDirectory时,指定的目录将用来缓存loader的执行结果。之后的 webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的Babel重新编译过程。如果设置了一个空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 将使用默认的缓存目录 node_modules/.cache/babel-loader,如果在任何根目录下都没有找到 node_modules 目录,将会降级回退到操作系统默认的临时文件目录。

7.2 执行生产编译 默认已开启Tree Shaking

通过依赖,则可以直接使用打包后代码,而不需webpack去循环依赖

html-webpack-plugin 产出html文件

查找当前目录下的node_modules目录,看是否有匹配项,如有,命中文件 寻找父目录的下的node_modules,如有,命中文件 按照这个规则一直往父目录搜索直到到根目录下的node_modules

5.DLL动态链接库

理论上我们项目的第三方依赖均应在自己的工程的node_modules下,所以我们可以设置查找目录,减少node的默认查找

es6模块

更精准的loader规则

// main.jsimport {sub} from './funs.js'sub();

更精准的mainFields

webpack --mode production

webpack构建中,需要大量的loader转换操作,很耗时,由于nodejs是单线程的,如果想更好利用cpu的多核能力,可以开启多个进程,同时对文件进行处理;可以看到在配置文件中,我们每次将文件交给happypack-loader去处理,然后由happypack去调度来执行文件的处理(happypack采用哪个loaders进行处理,是通过id知道的)

创建 import 或 require 的路径别名,来确保模块引入变得更简单。配置项通过别名来把原导入路径映射成一个新的导入路径 此优化方法会影响使用Tree-Shaking去除无效代码

使用HappyPack同时处理多个loader编译任务

1.动态加载模块 commonJS 是运行时加载 能够轻松实现懒加载,优化用户体验

 plugins: [ new webpack.DllReferencePlugin({ manifest: require('./dist/manifest.json') }) ],

5.3 将动态链接库文件加载到页面中

const path = require;const HappyPack = require;// 共享5个进程池const happyThreadPool = HappyPack.ThreadPool;module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve, }, module: { // noParse: [/react.production.min.js$/], rules: [{ test: /.js$/, // 和下面插件id一直,happypack才可以找到 use: ['happypack/loader?id=babel'], include: path.resolve }] }, plugins: [ // 插件可以实例化多个 new HappyPack({ // 与上面对应 id: 'babel', // 实际要使用的loader loaders: ['babel-loader?cacheDirectory'], // 默认开启进程数 threads: 3, // 是否允许happyPack打印日志 verbose: true, // 共享进程数,如果你使用超过一个happyplugin,官方建议共享进程池 threadPool: happyThreadPool }) ],};
resolve: { extensions: ['.js', '.vue']}

减少监听文件

也可以在给定对象的键后的末尾添加 $,以表示精准匹配:

补充5-文件监听原理

4.模块的引用 es6模块中,导出的并不是模块的值得拷贝,而是这个模块的引用

import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin'; module.exports = { plugins: [ new ParallelUglifyPlugin({ test, include, exclude, cacheDir, workerCount, sourceMap, uglifyJS: { }, uglifyES: { } }), ],};
webpack --mode production //此时funs.js中没有被用到的代码并没打包进来 而被剔除出去了
module.exports = { extensions: ['.js', '.jsx', '.ts', '.tsx'],}

extensions: [".js", ".json"]

happypack提供的loader,是对文件实际匹配的处理loader。这里happypack提供的loader与plugin的衔接匹配,则是通过id=happypack来完成。

数量更多类型的文件尽量放在前面

npm i html-webpack-plugin html-webpack-include-assets-plugin -D

为什么这个不重要,我发现react直接导出的index.js则是根据环境判断使用哪份代码,目测来看并不需要进行循环依赖的处理

剔除JavaScript中用不上的代码。它依赖静态的ES6模块化语法,例如通过impot和export导入导出

本文由美高梅游戏平台网站发布于美高梅4858永利777,转载请注明出处:webpack4.0打包优化策略整理小结_javascript技巧_脚本之家

关键词: