Webpack 常用知识点总结

webpack 是一个模块打包器。webpack 的主要目标是将 javaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)。

随着 webpack 不断地发展,webpack 配置变得越来越简单,构建速度也越来越快,官方文档上说 webpack4 比 webpack3 构建速度快了 98%,这还不仅如此,官方标识在 webpack5 中,会使用多进程构建,进一步优化构建速度。

本文已同步到个人博客,欢迎 start,谢谢。

Webpack 核心概念

  • 入口(entry)
  • 输出(output)
  • loader
  • 插件(plugins)

入口

入口是 webpack 构建开始的地方,通过入口文件,webpack 可以找到入口文件所依赖的文件,并逐步递归,找出所有依赖的文件。

module.exports = {entry: "./path/to/my/entry/file.js"
};

输出

output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。

const path = require("path");module.exports = {entry: "./path/to/my/entry/file.js",output: {path: path.resolve(__dirname, "dist"),filename: "my-first-webpack.bundle.js"}
};

loader

webpack 自身只支持 JavaScript。而 loader 能够让 webpack 处理那些非 JavaScript 文件,并且先将它们转换为有效的模块,然后添加到依赖图中,这样就可以提供给应用程序使用。

loader 的使用

const path = require("path");module.exports = {output: {filename: "my-first-webpack.bundle.js"},module: {rules: [{// 根据后缀名匹配需要处理的文件test: /\.txt$/,// 使用对应的loader处理文件use: "raw-loader"}]}
};

loader 的编写

loader 其实就是一个 function,接收一个参数 source,就是当前的文件内容,然后稍加处理,就可以 return 出一个新的文件内容。

const loaderUtils = require("loader-utils");module.exports = function(source) {// 获取loader中传递的配置信息const options = loaderUtils.getOptions(this);// 返回处理后的内容this.callback(null, "/ *增加一个注释 */" + source);// 也可以直接return// return "/ *增加一个注释 */" + source;
};

插件

插件其实就是一个类,通过监听 webpack 执行流程上的钩子函数,可以更精密地控制 webpack 的输出,包括:打包优化、资源管理和注入环境变量。

插件的使用

const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {module: {rules: [{ test: /\.txt$/, use: "raw-loader" }]},plugins: [new HtmlWebpackPlugin({ template: "./src/index.html" })]
};

编写自定义插件

我们可以利用 webpack 提供的钩子函数,编写自定义插件,相当于监听 webpack 的事件,做出对应的响应,webpack 是通过Tapable进行事件流管理的。

class APlugin {// apply方法,会在new plugin后被webpack自动执行。apply(compiler) {// 可以在任意的钩子函数中去触发自定义事件,也可以监听其他事件:compiler.hooks.xxxxcompiler.hooks.compilation.tap("APlugin", compilation => {compilation.hooks.afterOptimizeChunkAssets.tap("APlugin", chunks => {//   这里只是简单的打印了chunks,你如果有更多的想法,都可以在这里实现。console.log("打印chunks:", chunks);});});}
}

Webpack 调优

在 webpack4 发布后,相比 webpack3 的构建进行了高效地优化,速度提高了 98%,一些常规优化 webpack 都已经帮我们做了,使得 webpack 变得越来越简单,甚至可以达到零配置,但是对于零配置而言,不能满足全部需求,所以还是建议进行手动配置。

使用 mode 配置项

最懒人的写法,在 webpack 配置项中 mode = production ,webpack 就帮我们把常用的配置都配好了,而且完全可以胜任大部分需求。

module.exports = {mode: "production"
};

使用该配置后,webpack 会将 process.env.NODE_ENV 的值设为 production。

并且还会帮我们配置好以下插件:

  • FlagDependencyUsagePlugin(标记没有用到的依赖)
  • FlagIncludedChunksPlugin(标记用到的依赖)
  • ModuleConcatenationPlugin(scope hoisting)
  • NoEmitOnErrorsPlugin(遇到错误代码不跳出)
  • OccurrenceOrderPlugin(给生成的 chunkid 排序)
  • SideEffectsFlagPlugin
  • uglifyjs-webpack-plugin(压缩 js)

拆分文件

如果不使用 plugin,webpack 会把所有文件都打包在一个 js 文件中,这往往会使得文件很大,加载时间会变得很长,我们可以配置 optimization.splitChunks 来设置拆分文件规则。

这是 webpack 默认的配置,也可以根据自己需求做对应修改。

module.exports = {optimization: {splitChunks: {chunks: "async", // 参数可能是:all,async和initial,这里表示拆分异步模块。minSize: 30000, // 如果模块的大小大于30kb,才会被拆分minChunks: 1,maxAsyncRequests: 5, // 按需加载时最大的请求数,意思就是说,如果拆得很小,就会超过这个值,限制拆分的数量。maxInitialRequests: 3, // 入口处的最大请求数automaticNameDelimiter: "~", // webpack将使用块的名称和名称生成名称(例如vendors~main.js)name: true, // 拆分块的名称cacheGroups: {// 缓存splitchunksvendors: {test: /[\\/]node_modules[\\/]/,priority: -10},default: {minChunks: 2, // 一个模块至少出现2次引用时,才会被拆分priority: -20,reuseExistingChunk: true}}}}
};

使用 Happypack

纵观 webpack 构建流程,我们可以发现整个构建过程主要花费时间的部分也就是递归遍历各个 entry 然后寻找依赖逐个编译的过程,每次递归都需要经历 String->AST->String 的流程,经过 loader 还需要处理一些字符串或者执行一些 JS 脚本,介于 node.js 单线程的壁垒,webpack 构建慢一直成为它饱受诟病的原因。

// @file: webpack.config.js
var HappyPack = require("happypack");
var happyThreadPool = HappyPack.ThreadPool({ size: 5 });module.exports = {// ...plugins: [new HappyPack({id: "jsx",threadPool: happyThreadPool,loaders: ["babel-loader"]}),new HappyPack({id: "styles",threadPool: happyThreadPool,loaders: ["style-loader", "css-loader", "less-loader"]})]
};exports.module.rules = [{test: /\.js$/,use: "happypack/loader?id=jsx"},{test: /\.less$/,use: "happypack/loader?id=styles"}
];

Happypack 实际上是使用了 node processes 执行多线程构建,可以让多个 loader 并行执行,从而加快构建。

使用 DllPlugin

DllPlugin:用于打包单独的动态链接库文件。

DllReferencePlugin:用于在主要的配置文件中引入 DllPlugin 插件打包好的动态链接库文件。

这里需要建 2 个配置文件,先执行 webpack.dll.config.js,生成 mainfest,然后再执行 webpack.config.js 打包文件,可以看到,构建速度有了非常大的提升。

动态链接库配置:

// webpack.dll.config.js
// 这里配置DllPlugin,生成mainifest
module.exports = {entry:{// 将react相关,放入一个单独的动态链接库中react:['react','react-dom']},output:{filename:'[name].dll.js'},plugins:[new webpack.DllPlugin({name: '_dll_[name]',path: path.join(__dirname, '[name].manifest.json'),);]
};

使用打包后的动态链接库:

// webpack.config.js
// 这里配置DllPlugin,生成mainifest
module.exports = {plugins:[new webpack.DllReferencePlugin({manifest: require('./react.manifest.json')});]
};

其他优化方法

常规优化

1、在处理 loader 时,配置 include,缩小 loader 检查范围。

2、使用 alias 可以更快地找到对应文件。

3、如果在 require 模块时不写后缀名,默认 webpack 会尝试.js,.json 等后缀名匹配,extensions 配置,让 webpack 少做一点后缀匹配。

4、thread-loader 可以将非常消耗资源的 loaders 转存到 worker pool 中。

5、使用 cache-loader 启用持久化缓存。使用 package.json 中的 "postinstall" 清除缓存目录。

开发环境

1、选择合理额 Devtool 在大多数情况下,cheap-module-eval-source-map 是最好的选择。

2、开发阶段一般不需要进行压缩合并,提权单独文件等操作。

3、webpack 会在输出文件中生成路径信息。然而在打包数千个模块的项目中,会导致造成垃圾回收性能压力。在 options.output.pathinfo 设置中关闭.

4、在开发阶段,可以直接引用 cdn 上的库文件,使用 externals 配置全局对象,避免打包。

生产环境

1、静态资源上 cdn。

2、使用 tree shaking,只打包用到的模块,删除没有用到的模块。

3、配置 scope hoisting 作用域提升,将多个 IIFE 放在一个 IIFE 中。

相关的代码如下:

module.exports = {output: {// 静态资源上cdnpublicPath: "//xxx/cdn.com",// 不生成「所包含模块信息」的相关注释pathinfo: false},module: {rules: [{test: /\.txt$/,use: "raw-loader",// 缩小loader检查范围include: path.join(__dirname, "src")}]},plugins: [// 开启scope hoistingnew ModuleConcatenationPlugin()],resolve: {// 使用别名,加快搜索alias: {"~": path.resolve(__dirname, "../src")},// 配置用到的后缀名,方便webpack查找extensions: ["js", "css"]},// 开发阶段引用cdn上文件,可以避免打包库文件externals: {vue: "Vue","element-ui": "ELEMENT"}
};

Webpack 运行原理

webpack 在运行时大致分为这几个阶段:

1、读取 webpack.config.js 配置文件,生成 compiler 实例,并把 compiler 实例注入 plugin 中的 apply 方法中。

2、读取配置的 Entries,递归遍历所有的入口文件。

3、对入口文件进行编译,开始 compilation 过程,使用 loader 对文件内容编译,再将编译好的文件内容解析成 AST 静态语法树。

4、递归依赖的模块,重复第 3 步,生成 AST 语法树,在 AST 语法树中可以分析到模块之间的依赖关系,对应做出优化。

5、将所有模块中的 require 语法替换成__webpack_require__来模拟模块化操作。

6、最后把所有的模块打包进一个自执行函数(IIFE)中。

流程图

这张图画的很好,把webpack的流程画的很细致。

图片是参考文章Webpack揭秘——走向高阶前端的必经之路里的,如有侵权,请联系我,马上删除。


::: tip 参考资料
webpack 官网

Webpack 揭秘——走向高阶前端的必经之路
:::

Webpack 常用知识点总结相关推荐

  1. webpack常用知识点

    1.pc端中后台应用打包 npm组件在浏览器的js中不能直接引入,所以要借助webpack等工具 jsx在浏览器端也是无法直接解析,要用工具转换 页面打包速度和资源体积问题 4.构建工具需要原因: 转 ...

  2. Vue 2.x 常用知识点笔记(万字笔记)

    Vue 2.x 笔记 常用知识点笔记,有错误欢迎指点哦~ 字数超过了一万字,得细品 目录 Vue 2.x 笔记 1.新建Vue实例 2.阻止生成生产提示 3.模板语法 3.1 插值语法 3.2 指令语 ...

  3. javaScript常用知识点有哪些

    javaScript常用知识点有哪些 一.总结 一句话总结:int = ~~myVar, // to integer | 是二进制或, x|0 永远等于x:^为异或,同0异1,所以 x^0 还是永远等 ...

  4. ES6常用知识点概述

    前言 国庆假期已过一半,来篇干货压压惊. ES6,并不是一个新鲜的东西,ES7.ES8已经赶脚了.但是,东西不在于新,而在于总结.每个学前端的人,身边也必定有本阮老师的<ES6标准入门>或 ...

  5. webpack常用命令总结

    Webpack 常用命令总结 构建命令,webpack的常用参数 $ webpack --config webpack.min.js //另一份配置文件$ webpack --display-erro ...

  6. list python 访问 键值对_基础|Python常用知识点汇总(中)

    字符串字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.1.创建字符串 str1 = 'Hello World!' str2 = "Hello W ...

  7. matplotlib一些常用知识点的整理,

    本文作为学习过程中对matplotlib一些常用知识点的整理,方便查找. 强烈推荐ipython 无论你工作在什么项目上,IPython都是值得推荐的.利用ipython --pylab,可以进入Py ...

  8. oracle 常用知识点整理

    转 :  oracle 常用知识点 原文链接:http://blog.csdn.net/weijiaxiaobao/article/details/51323573 Oracle 是一个庞大的系统,里 ...

  9. php常用技术与thinkphp5,thinkPHP5框架路由常用知识点汇总

    本文实例讲述了thinkPHP5框架路由常用知识点.分享给大家供大家参考,具体如下: 一.路由的模式 普通模式(默认pathinfo,不解析路由) 'url_route_on' => false ...

最新文章

  1. 单页面与多页面的区别及优缺点
  2. python递归函数错误使用方式
  3. centos安装anaconda_每天三分钟之TensorFlow学习03:Win下安装TF2
  4. C语言两班平均成绩,用C语言编程平均分数
  5. 单体应用架构——垂直应用架构———分布式架构———SOA架构———微服务架构
  6. spring mvc学习(3):建立第一个动态web项目
  7. H264基本概念之 宏块、片和片组
  8. sqlserver服务启动后停止,传递给数据库 'master' 中的日志扫描操作的日志扫描号无效...
  9. UML从需求到实现----用例
  10. edittext 无法输入内容_掌握其中1个Excel小技巧,你就不用再担心会重复录入内容了。...
  11. Alfred Remote初体验
  12. ubuntu7.10下配置java 6和mysql
  13. SQL Server 2005两种快照隔离机制的比较
  14. 曾经,我们有一个芝麻大小的梦想
  15. matlab 倒谱ceptrum,倒谱法求共振峰
  16. python interpreter是什么_如何写一个Python Interpreter | 学步园
  17. Web报表系统葡萄城报表:报表设计
  18. 如何实现一个二维码支持微信支付和支付宝支付
  19. 亲自操作,有用的win10遇到“已禁用输入法”无法启动中文输入法的问题-提示已禁用输入法解决方案
  20. python声纹识别_【kaldi学习.4】Aishell V1(说话人识别、声纹识别)中的run.sh详解...

热门文章

  1. 《Microduino实战》——3.6 RGB彩色LED——彩色的世界
  2. Android 11源码 Framework修改默认usb连接模式为MTP模式
  3. 用开源力量抗击新冠疫情!腾讯作为创始成员加入Linux基金会公共卫生计划
  4. python基础知识
  5. cnpm的安装(超级详细版)
  6. 【NodeJS】安装
  7. 安装 Node.js
  8. 轩迅汇如何做好个人定位?定位越早,受益越多
  9. Android App签名(证书)校验过程源码分析
  10. java去掉字符串的空格_如何去掉字符串中的空格?