不折腾的前端,和咸鱼有什么区别css
返回目录
都 2020 了,不会点 Webpack 好像有点说不过去。html
可是事实上若是不是分配到【架构组】之类的团体中,感受接触 Webpack 的几率会少点吧。前端
就比如 jsliang 在上家公司,就没机会接触 Webpack,都是用这别人已经配置好的方案,纯粹作一个业务仔~vue
返回目录
Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler
)。node
当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph
),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle
。react
因此,它的本质是一个模块打包器,其工做是将每一个模块打包成相应的 bundle
。webpack
返回目录
mode
:模式。对应有开发模式、生产模式等entry
:入口output
:出口loader
:模块转换器,用于把模块原内容按照需求转换成新内容。Webpack 对于 .jpg
、.txt
等内容没法处理,就须要 file-loader
、url-loader
等进行协助处理。plugins
:扩展插件,在 Webpack 构建流程中的特定时机注入拓展逻辑来改变构建结果或者作其余你想作的事情。返回目录
Webpack 就像一条生产线,要通过一系列处理流程后才能将源文件转换成输出结果。nginx
这条生产线上的每一个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 git
Webpack
的运行流程是一个串行的过程,从启动到结束会依次执行如下流程:github
Shell
语句中读取与合并参数,得出最终的参数Compiler
对象,加载全部配置的插件,执行对象的 run
方法开始执行编译entry
找出全部的入口文件Loader
对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到全部入口依赖的文件都通过了本步骤的处理Loader
翻译完全部模块后,获得了每一个模块被翻译后的最终内容以及它们之间的依赖关系Chunk
,再把每一个 Chunk
转换成一个单独的文件加入到输出列表,这步是能够修改输出内容的最后机会简单来讲:
Plugin
,实例化 Compiler
(钩子)Entry
出发,针对每一个 Module
(模块)串行调用对应的 Loader
去翻译文件的内容,再找到该 Module
依赖的 Module
,递归地进行编译处理Module
组合成 Chunk
,将 Chunk
转换成文件,输出到文件系统中(Chunk
就是打包过程当中,入口模块引用其余模块,模块再引用模块,这个关系链链接的 Module
就造成了 Chunk
)在这个过程当中,Webpack
会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,而且插件能够调用 Webpack
提供的 API
改变 Webpack
的运行结果。
返回目录
指定打包⼊口文件,有三种不一样的形式:string | object | array
。
一对一:一个入口、一个打包文件
module.exports = { entry: './src/index.js' }
多对一:多个入口、一个打包文件
module.exports = { entry: [ './src/index1.js', './src/index2.js', ] }
多对多:多个入口、多打包文件
module.exports = { entry: { 'index1': "./src/index1.js", 'index2': "./src/index2.js" } }
返回目录
打包后的文件位置。
module.exports = { ..., output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", filename: "[name].js" } }
entry
为对象),则不能使用单文件出口,须要使用下面的方式Webpack
内置的变量占位符:[name]
返回目录
loader
的执行顺序是从右向左执行的,也就是后面的 loader
先执行。
假若有配置:
// webpack.config.js module.exports = { //... module: { rules: [ { test: /\.(le|c)ss$/, use: ['style-loader', 'css-loader', 'less-loader'], exclude: /node_modules/, }, ], }, };
那就是先处理 less-loader
,再处理 css-loader
,最后处理 style-loader
。
返回目录
file-loader
:当引入的文件是 .png
、.txt
等时,能够经过 file-loader
解析项目中的 url
引入。根据配置将文件拷贝到相应的路径,并修改打包后文件的引入路径,让它指向正确的文件。url-loader
:url-loader
封装了 file-loader
且能够不依赖于 file-loader
单独使用,而且能够配置 limit
。对小于 limit
大小的图片转换成 Base64
,大于 limit
的时候使用 file-loader
里的方法。返回目录
tslint-loader
:经过 TSLint 检查 TypeScript 代码eslint-loader
:经过 ESLint 检查 JavaScript 代码返回目录
html-withimg-loader
:处理 HTML 中的图片返回目录
style-loader
:动态建立 style
标签,将 CSS 代码插入到 head
中。css-loader
:负责处理 @import
、url
等语句。例如 import css from 'file.css'
、url(image.png)
。postcss-loader
:负责进一步处理 CSS 文件,好比添加浏览器前缀,压缩 CSS 等。less-loader
:将 .less
文件内容转换成 CSS。sass-loader
:将 .sass
文件内容转换成 CSS。返回目录
babel-loader
:将 JS 代码向低版本转换,咱们须要使用 babel-loader
。ts-loader
:将 TypeScript 转换成 JavaScript返回目录
返回目录
clean-webpack-plugin
:打包前自动清理 dist
目录,防止文件残留。copy-webpack-plugin
:将单个文件或者整个目录复制到构建目录mini-css-extract-plugin
:将 CSS 抽离出来单独打包而且经过配置能够设置是否压缩。html-webpack-plugin
:这个插件能够配置生成一个 HTML5 文件,其中 script
标签包含全部 Webpack 包。若是你设置多个入口点,你能够据此实现多页面应用打包。返回目录
webpack-dashboard
:能够更友好的展现相关打包信息。webpack-merge
:提取公共配置,减小重复配置代码speed-measure-webpack-plugin
:简称 SMP,分析出 Webpack 打包过程当中 Loader 和 Plugin 的耗时,有助于找到构建过程当中的性能瓶颈。size-plugin
:监控资源体积变化,尽早发现问题HotModuleReplacementPlugin
:模块热替换返回目录
Loader
Loader
本质上就是一个函数,对接收到的内容进行转换,返回转换后的结果。
由于 Webpack
只认识 JavaScript,因此 Loader
就成了翻译官,对不一样类型的资源进行处理。
就比如 file-loader
或者 url-loader
,配置以后就能够正确引用 png
等格式的图片、txt
等格式文件。
又比如 style-loader
以及 css-loader
,引用后就能够对 CSS 内容进行预编译处理。
Plugin
Plugin
就是插件,就比如 jsliang 编写的 VS Code 插件同样,Plugin
拓展了 Webpack
的功能。
Plugin
就是在 Webpack
的生命周期中进行各类操做,从而达到使用者目的插件。
就比如 html-webpack-plugin
,配合多入口形式使用以后,就能够实现多页面应用的功能。
又比如 clean-webpack-plugin
实现打包以前清空 dist
目录,copy-webpack-plugin
能够将单个文件或者整个目录复制到构建目录。
返回目录
resolve
配置 Webpack 如何寻找模块所对应的文件。
Webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你能够根据本身的须要修改默认的规则。
// webpack.config.js module.exports = { //.... resolve: { modules: ['./src/components', 'node_modules'] // 从左到右依次查找 } }
resolve.modules
:配置 Webpack 去哪些目录下寻找第三方模块,默认状况下,只会去 node_modules
下寻找,若是你在项目中某个文件夹下的模块常常被导入,不但愿写很长的路径,那么就能够经过配置 resolve.modules
来简化。resolve.alias
:配置项经过别名把原导入路径映射成一个新的导入路径。resolve.extensions
:适配多端的项目中,可能会出现 .web.js
, .wx.js
,例如在转 Web 的项目中,咱们但愿首先找 .web.js
,若是没有,再找 .js
。extensions: ['web.js', '.js']
。返回目录
如何从 0 开始配置一个属于本身的 Webpack 脚手架呢?那就涉及到选型问题。
返回目录
返回目录
['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
less less-loader
:解析 .less
文件postcss-loader autoprefixer
:对 flex
布局等进行前缀补充返回目录
file-loader
:解析 .txt
、.png
、.md
等格式文件url-loader
:limit: 1024
,判断大小是否处理成 base64
格式返回目录
url-loader
返回目录
glob
entry
和 htmlwebpackplugin
动态生成返回目录
devtool: "cheap-module-eval-source-map
devtool: "cheap-module-source-map"
返回目录
devServer
HMR
(热模块替换,Hot Module Replacement)HMR
,须要 Webpack
配合返回目录
安装:npm i babel-loader @babel/core @babel-preset-env -D
@babel/core
:babel
核心babel-loader
:babel
和 Webpack
的链接桥梁babel-preset-env
:输出什么样的代码,用它来解决babel-loader
:解析 ES6+@babel/polyfill
:垫片。包含全部 ES6+ 新特性代码.babelrc
返回目录
react react-dom
@babel/preset-react
返回目录
loader
的文件范围:loader
的 include
配置,能够指定 src
目录,减小检查范围。resolve.modules
配置:配置 Webpack
去哪些目录下寻找第三方模块,默认 node_modules
。MiniCssExtractPlugin
hash
、chunkhash
、contenthash
区别
hash
做用域 JS、CSS,图片的 hash
有区别,每次打包构建都会变化一次。chunkhash
以 chunk
为单位,修改了那部分就改动哪部分的 hash
。(同时依赖的模块也会改变 hash
)contenthash
只有本身内容发生改变,才发生改变(区别于 chunkhash
。chunkhash
;CSS 适用于 contenthash
;Image 适用于 hash
optimize-css-assets-webpack-plugin
和 cssnano
html-webpack-plugin
img-webpack-loader
Webpack
配置:分离 base.config
、dev.config
、mpa.config
和 pro.config
4 个,经过 merge
进行 config
配置的合并更多看这里:
返回目录
Webpack
解析器Webpack loader
Webpack plugin
返回目录
懒加载或者按需加载,是一种很好的优化网页或应用的方式。
这种方式其实是先把你的代码在一些逻辑断点处分离开,而后在一些代码块中完成某些操做后,当即引用或即将引用另一些新的代码块。
这样加快了应用的初始加载速度,减轻了它的整体体积,由于某些代码块可能永远不会被加载。
返回目录
代码分割(code splitting
)是指:将脚本中无需当即调用的代码在代码构建时转变为异步加载的过程。
在 Webpack 构建时,会避免加载已声明要异步加载的代码,异步代码会被单独分离出一个文件,当代码实际调用时被加载至页面。
代码分割技术的核心是 异步加载资源。
可喜的是,浏览器容许咱们这么作,W3C stage 3
规范: whatwg/loader 对其进行了定义:你能够经过 import()
关键字让浏览器在程序执行时异步加载相关资源。
在 Vue 中,能够直接使用 import()
关键字作到这一点,而在 React 中,你须要使用 react-loadable
去完成一样的事。
返回目录
children chunk
)import
)print.js
console.log('输出 1'); export default () => { console.log('输出 2'); };
index.js
const btn = document.querySelector('.btn'); btn.onclick = import('./print.js').then((module) => { const print = module.default; print(); });
返回目录
Vue 的特色就是 SPA - Single Page Application(单页应用程序)。
只有第一次加载页面,之后的每次页面切换,只须要进行组件替换。
它减小了请求次数,加快页面响应速度,下降对服务器压力等等。
可是,由于 Vue 是 SPA,因此首页第一次加载时会把全部组件以及组件相关资源所有加载,从而致使网站首页打开速度变慢,下降用户体验。
Vue 项目中,能够结合 Webpack,在 vue-router
经过 import
进行动态加载:
const routes = [{ path: '/', name: 'Home', component: () => import('../views/Home.vue') }];
返回目录
刷新咱们通常分为两种:
window.location.reload()
。WDS
(Webpack-dev-server
)的模块热替换,只须要局部刷新页面上发生变化的模块,同时能够保留当前的页面状态,好比复选框的选中状态、输入框的输入等。Webpack
的热更新又称热替换(Hot Module Replacement
),缩写为 HMR
。
这个机制能够作到不用刷新浏览器而将新变动的模块替换掉旧的模块。
返回目录
在 Webpack 的 webpack.config.js
中:
devServer
的 hot
为 true
plugins
中增长 new webpack.HotModuleReplacementPlugin()
// webpack.config.js const webpack = require('webpack'); module.exports = { //.... devServer: { hot: true }, plugins: [ new webpack.HotModuleReplacementPlugin() // 热更新插件 ] }
而且在入口文件配置:
if(module && module.hot) { module.hot.accept() }
此时修改代码的时候,只有对应部分的内容才会相应更新。
返回目录
HMR
的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff
(chunk
须要更新的部分)。
实际上 webpack-dev-server
(WDS
)与浏览器之间维护了一个 Websocket
,当本地资源发生变化时,WDS
会向浏览器推送更新,并带上构建时的 hash
,让客户端与上一次资源进行对比。
客户端对比出差别后会向 WDS
发起 Ajax
请求来获取更改内容(文件列表、hash
),这样客户端就能够再借助这些信息继续向 WDS
发起 jsonp
请求获取该 chunk
的增量更新。
后续的部分(拿到增量更新以后如何处理?哪些状态该保留?哪些又须要更新?)由 HotModulePlugin
来完成,提供了相关 API
以供开发者针对自身场景进行处理,像 react-hot-loader
和 vue-loader
都是借助这些 API
实现 HMR
。
返回目录
文件指纹是打包后输出的文件名的后缀,对应着 3 种 hash
。
hash
是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的 hash
值都会更改,而且所有文件都共用相同的 hash
值。(粒度整个项目)chunkhash
是根据不一样的入口进行依赖文件解析,构建对应的 chunk
(模块),生成对应的 hash
值。只有被修改的 chunk
(模块)在从新构建以后才会生成新的 hash
值,不会影响其它的 chunk
。(粒度 entry
的每一个入口文件)contenthash
是跟每一个生成的文件有关,每一个文件都有一个惟一的 hash
值。当要构建的文件内容发生改变时,就会生成新的 hash
值,且该文件的改变并不会影响和它同一个模块下的其它文件。(粒度每一个文件的内容)返回目录
source map
是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具有良好的可读性,想要调试源码就须要 soucre map
。
map
文件只要不打开开发者工具,浏览器是不会加载的。
线上环境通常有三种处理方案:
hidden-source-map
:借助第三方错误监控平台 Sentry
使用nosources-source-map
:只会显示具体行数以及查看源代码的错误栈。安全性比 source map
高source map
:经过 nginx
设置将 .map
文件只对白名单开放(公司内网)注意:避免在生产中使用 inline-
和 eval-
,由于它们会增长 bundle
体积大小,并下降总体性能。
返回目录
在 Webpack 简单实现中,简单的作了下如何将一份代码进行打包:
babel
完成代码转换,并生成单个文件的依赖返回目录
本系列参考文献有 51 篇文章。
返回目录
其余:
2020 年文章:
2019 年文章:
2018 年文章:
2017 文章:
返回目录
2019 年文章:
2018 年文章:
2017 年文章:
返回目录
返回目录
返回目录
jsliang 的文档库由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议 进行许可。<br/>基于 https://github.com/LiangJunrong/document-library 上的做品创做。<br/>本许可协议受权以外的使用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处得到。