本文共 13319 字,大约阅读时间需要 44 分钟。
1.1.1 include & exclude
module:{ rules:[ { test:/\.js$/, use:['babel-loader?cacheDirectory'],+ include:path.resolve(__dirname,'src'),+ exclude:/node_modules/ } ] }复制代码
1.1.2 resolve.modules
resolve: { modules: [path.resolve(__dirname, 'node_modules')]},复制代码
1.1.3 resolve.mainFields
mainFields
用于配置第三方模块使用那个入口文件
resolve.alias
配置项通过别名来把原导入路径映射成一个新的导入路径 此优化方法会影响使用Tree-Shaking
去除无效代码
alias: { 'react': path.resolve(__dirname, './node_modules/react/cjs/eact.production.min.js') }复制代码
在导入语句没带文件后缀时,Webpack会自动带上后缀后去尝试询问文件是否存在 默认后缀是 extensions: ['.js', '.json']
resolve: {+ extensions: ['js']},复制代码
module.noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理
module: {+ noParse: [/react\.min\.js/] }复制代码
被忽略掉的文件里不应该包含 import 、 require 、 define 等模块化语句
.dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据
module.exports = { entry: { react: ['react'] //react模块打包到一个动态连接库 }, output: { path: path.resolve(__dirname, 'dist'), filename: '[name].dll.js', //输出动态连接库的文件名称 library: '_dll_[name]' //全局变量名称 }, plugins: [ new webpack.DllPlugin({ name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值 path: path.join(__dirname, 'dist', '[name].manifest.json') }) ]}复制代码
webpack --config webpack.dll.config.js --mode production复制代码
plugins: [+ new webpack.DllReferencePlugin({+ manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),+ }) ],复制代码
webpack --config webpack.config.js --mode development复制代码
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
npm i happypack@next -D复制代码
module: { rules: [{ test: /\.js$/, //把对.js文件的处理转交给id为babel的HappyPack实例 + use: 'happypack/loader?id=babel', include: path.resolve(__dirname, 'src'), exclude: /node_modules/ }, { //把对.css文件的处理转交给id为css的HappyPack实例 test: /\.css$/,+ use: 'happypack/loader?id=css', include: path.resolve(__dirname, 'src') }], noParse: [/react\.min\.js/] },复制代码
plugins: [ //用唯一的标识符id来代表当前的HappyPack是用来处理一类特定文件 new HappyPack({ id: 'babel', //如何处理.js文件,和rules里的配置相同 loaders: [{ loader: 'babel-loader', query: { presets: [ "env", "react" ] } }] }), new HappyPack({ id: 'css', loaders: ['style-loader', 'css-loader'], threads: 4, //代表开启几个子进程去处理这一类型的文件 verbose: true //是否允许输出日子 }) ],复制代码
ParallelUglifyPlugin
可以把对JS文件的串行压缩变为开启多个子进程并行执行
npm i -D webpack-parallel-uglify-plugin复制代码
new ParallelUglifyPlugin({ workerCount: 3, //开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1 uglifyJS: { output: { beautify: false, //不需要格式化 comments: false, //不保留注释 }, compress: { warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告 drop_console: true, // 删除所有的 `console` 语句,可以兼容ie浏览器 collapse_vars: true, // 内嵌定义了但是只用到一次的变量 reduce_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值 } }, })复制代码
我们可以监听到本地源码文件发生变化时,自动重新构建出可运行的代码后再刷新浏览器
+ watch: true, //只有在开启监听模式时,watchOptions才有意义+ watchOptions: {+ ignored: /node_modules/,+ aggregateTimeout: 300, //监听到变化发生后等300ms再去执行动作,防止文件更新太快导致编译频率太高+ poll: 1000 //通过不停的询问文件是否改变来判断文件是否发生变化,默认每秒询问1000次+ }复制代码
aggregateTimeout
配置devServer: { contentBase: './dist',+ inline: true },复制代码
webpack负责监听文件变化,webpack-dev-server负责刷新浏览器 这些文件会被打包到chunk中,它们会代理客户端向服务器发起WebSocket连接
+ [19] (webpack)-dev-server/client/overlay.js 3.58 KiB {0} [built]+ [21] (webpack)-dev-server/client/socket.js 1.05 KiB {0} [built]+ [22] ./node_modules/loglevel/lib/loglevel.js 7.68 KiB {0} [built]+ [24] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]+ [31] ./node_modules/url/url.js 22.8 KiB {0} [built]+ [32] (webpack)-dev-server/client?http://localhost:8080 7.75 KiB {0} [built]+ [33] multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js 40 bytes {0} [built]复制代码
模块热替换(Hot Module Replacement)的技术可在不刷新整个网页的情况下只更新指定的模块 原理是当一个源码发生变化时,只重新编译发生变化的模块,再用新输出的模块替换掉浏览器中对应的老模块
devServer: {+ hot:true }复制代码
[./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built] [0] multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/index.js 52 bytes {main} [built][./node_modules/webpack/hot/dev-server.js] (webpack)/hot/dev-server.js 1.66 KiB {main} [built][./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 77 bytes {main} [built]复制代码
if (module.hot) { module.hot.accept('./index.js', function () { console.log('accept index.js'); });}复制代码
优化模块热替换浏览器日志
plugins: [+ new webpack.NamedModulesPlugin(),+ new webpack.HotModuleReplacementPlugin(),]复制代码
在开发网页的时候,一般都会有多套运行环境,例如:
if(process.env.NODE_ENV == 'production'){ console.log('生产环境');}else{ console.log('开发环境');}复制代码
当你使用process模块的时候,webpack会把process模块打包进来
+ new webpack.DefinePlugin({+ 'process.env': {+ NODE_ENV:JSON.stringify('production')+ }+ }),复制代码
定义环境变量的值时用 JSON.stringify 包裹字符串的原因是环境变量的值需要是一个由双引号包裹的字符串,而 JSON.stringify('production')的值正好等于'"production"'
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),})复制代码
CDN 又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
output: { path: path.resolve(__dirname, 'dist'),+ filename: '[name]_[hash:8].js',+ publicPath: 'http://img.zhufengpeixun.cn' },复制代码
Tree Shaking
可以用来剔除JavaScript
中用不上的死代码。它依赖静态的ES6
模块化语法,例如通过import
和export
导入导出。
使用Tree
{ loader: 'babel-loader', query: { presets: [ [+ "env", {+ modules: false //含义是关闭 Babel 的模块转换功能,保留原本的 ES6 模块化语法+ } ], "react" ] } }复制代码
webpack --display-used-exports复制代码
+ const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); plugins: [+ new UglifyJSPlugin() ]复制代码
webpack --display-used-exports --optimize-minimizewebpack --mode production复制代码
大网站有多个页面,每个页面由于采用相同技术栈和样式代码,会包含很多公共代码,如果都包含进来会有问题
如何使用
entry: { pageA: './src/pageA', pageB: './src/pageB'},optimization: { splitChunks: { cacheGroups: { commons: { chunks: "initial", minChunks: 2, maxInitialRequests: 5, // The default limit is too small to showcase the effect minSize: 0 // This is example is too small to create commons chunks }, vendor: { test: /node_modules/, chunks: "initial", name: "vendor", priority: 10, enforce: true } } } },复制代码
Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快, 它又译作 "作用域提升",是在 Webpack3 中新推出的功能。
export default 'Hello';复制代码
import str from './hello.js';console.log(str);复制代码
var util = ('Hello');console.log(util);复制代码
函数由两个变成了一个,hello.js 中定义的内容被直接注入到了 main.js 中
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');module.exports = { resolve: { // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件 mainFields: ['jsnext:main', 'browser', 'main'] }, plugins: [ // 开启 Scope Hoisting new ModuleConcatenationPlugin(), ],};复制代码
--display-optimization-bailout复制代码
代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。 有三种常用的代码分离方法:
`entry: { index: './src/index.js', another: './src/another-module.js'}复制代码
splitChunks可以将公共的依赖模块提提取到一个新生成的 chunk.
optimization: { splitChunks: { cacheGroups: { commons: { chunks: "initial", minChunks: 2 }, vendor: { test: /node_modules/, chunks: "initial", name: "vendor", } }复制代码
用户当前需要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载 在给单页应用做按需加载优化时,一般采用以下原则:
document .getElementById('clickMe') .addEventListener('click', () => { import (/*webpackChunkName:"alert"*/ './alert').then(alert => { console.log(alert); alert.default('hello'); }); });复制代码
loaders: [ { loader: 'babel-loader', query: { presets: ["env", "stage-0", "react"] } } ]复制代码
webpack-dev-middleware 插件对更改的文件进行监控,编译,一般和 webpack-hot-middleware 配合使用,实现热加载功能
const path = require("path")const express = require("express")const webpack = require("webpack")const webpackDevMiddleware = require("webpack-dev-middleware")const webpackConfig = require('./webpack.config.js')const app = express(), DIST_DIR = path.join(__dirname, "dist"),// 设置静态访问文件路径 PORT = 9090, // 设置启动端口 complier = webpack(webpackConfig)app.use(webpackDevMiddleware(complier, {//绑定中间件的公共路径,与webpack配置的路径相同 publicPath: webpackConfig.output.publicPath, quiet: true //向控制台显示内容}))// 这个方法和下边注释的方法作用一样,就是设置访问静态文件的路径app.use(express.static(DIST_DIR))app.listen(PORT,function(){ console.log("成功启动:localhost:"+ PORT)})复制代码
webpack --profile --json > stats.json复制代码
Webpack 官方提供了一个可视化分析工具
当用 Webpack 去构建一个可以被其他模块导入使用的库时需要用到它们。
output.libraryTarget 是字符串的枚举类型,支持以下配置。
var (默认)
编写的库将通过 var 被赋值给通过 library 指定名称的变量。
假如配置了 output.library='LibraryName',则输出和使用的代码如下:
// Webpack 输出的代码var LibraryName = lib_code;// 使用库的方法LibraryName.doSomething();假如 output.library 为空,则将直接输出:复制代码
lib_code 其中 lib_code 代指导出库的代码内容,是有返回值的一个自执行函数。
commonjs
编写的库将通过 CommonJS 规范导出。
假如配置了 output.library='LibraryName',则输出和使用的代码如下:
// Webpack 输出的代码exports['LibraryName'] = lib_code;// 使用库的方法require('library-name-in-npm')['LibraryName'].doSomething();其中 library-name-in-npm 是指模块发布到 Npm 代码仓库时的名称。复制代码
commonjs2
编写的库将通过 CommonJS2 规范导出,输出和使用的代码如下:
// Webpack 输出的代码module.exports = lib_code;// 使用库的方法require('library-name-in-npm').doSomething();CommonJS2 和 CommonJS 规范很相似,差别在于 CommonJS 只能用 exports 导出,而 CommonJS2 在 CommonJS 的基础上增加了 module.exports 的导出方式。在 output.libraryTarget 为 commonjs2 时,配置 output.library 将没有意义。复制代码
this
编写的库将通过 this 被赋值给通过 library 指定的名称,输出和使用的代码如下:
// Webpack 输出的代码this['LibraryName'] = lib_code;// 使用库的方法this.LibraryName.doSomething();复制代码
window
编写的库将通过 window 被赋值给通过 library 指定的名称,即把库挂载到 window 上,输出和使用的代码如下:
// Webpack 输出的代码window['LibraryName'] = lib_code;// 使用库的方法window.LibraryName.doSomething();复制代码
global
编写的库将通过 global 被赋值给通过 library 指定的名称,即把库挂载到 global 上,输出和使用的代码如下:// Webpack 输出的代码global['LibraryName'] = lib_code;// 使用库的方法global.LibraryName.doSomething();作者:lio-mengxiang 链接:https://juejin.im/post/5c73893cf265da2dc13c88ee 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。