1、Webpack快速上手
yarn add webpack-cli --dev //安装webpack
"scripts": {
"build": "webpack"
},
在package里添加快捷指令,以后每次只需要yarn build就能进行打包
2、Webpack 配置文件
Webpack4以后的版本支持0配置打包,整个过程将按照约定src/index作为打包的入口,打包的结果会存在dist/main.js当中。
创建webpack.congig.js文件,写入一下配置
const path = require('path')//导入node中pash模块
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',//输出的文件名
path: path.join(__dirname, 'output')//拿到output的完整绝对路径
}
}
3、Webpack工作模式
Webpack4中新增了一个工作模式的用法,简化了webpack配置的复杂程度,可以理解为不同环境的几组预设的配置
const path = require('path')
module.exports = {
// 这个属性有三种取值,分别是 production、development 和 none。
// 1. 生产模式下,Webpack 会自动优化打包结果;
// 2. 开发模式下,Webpack 会自动优化打包速度,添加一些调试过程中的辅助;
// 3. None 模式下,Webpack 就是运行最原始的打包,不做任何额外处理;
mode: 'development',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
}
}
4、Webpack打包结果运行原理
不懂
5、Webpack资源模块加载
Webpack内部的loader只能处理JS文件,如果要处理其他类型的资源文件,那么就要添加其他的loader。loader是整个前端实现模块化的核心,通过不同的loader,就可以加载任何类型的资源。
如果要处理css文件就需要安装css-loader
yarn add css-loader --dev
安装完成后,需要在配置文件当中,rules添加相应的配置,如果配置了多个loader,执行顺序是从后往前
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.css',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
}
6、Webpack导入资源模块
根据代码需要动态导入资源,需要资源的不是应用,而是代码。 js驱动整个前端应用
7、Webpack loader集
webpack内部loader只能处理js文件,当遇到不是js当文件就需要下载其他loader来转换成js代码,实现加载。
1.文件资源加载器(处理图片资源文件)
yarn add file-loader --dev
module: {
rules: [
{
test: /.png$/,
use: 'file-loader'
}
]
}
文件加载器的工作过程 webpack在打包时,遇到了图片文件,根据配置文件中的配置,匹配对应的文件加载器,文件加载器开始工作,先是将导入的文件,拷贝到输出的目录,然后将文件拷贝到输出目录过后的路径作为当前模块的返回值返回,所需要的资源就发布出来了,然后就可以通过模块的导出成员拿到
2.URL加载器
通过Data URLs形式表示文件,Data URL是一种特殊的URL协议,可以用来直接表示一个文件,传统url需要服务器有一个对应的url文件,然后通过请求这个地址得到服务器上对应的文件。
Data URLs是一种当前url就可以直接去表示文件内容的方式,这种url当中的文本就已经包含了文件的内容,使用这种url就不会去发生任何的http请求。
最佳实践,小文件使用Data URLs,减少请求次数,大文件单独提取存放,提高加载速度
yarn add url-loader --dev
module: {
rules: [
{
test: /.png$/,
use: {
loader: 'url-loader',
options: {
limit: 10 * 1024 // 10 KB 将小于10kb的文件用Data URLs处理
//使用这个限制的方式,就一定要配上file-loader,超出限制的文件要用
//file-loader处理
}
}
}
]
}
8、Webpack常用加载器分类
1.编译转换类
- 会把加载到的资源模块转换成js代码 (css-loader)
2.文件操作类型
- 会把加载到的资源模块,拷贝到输出的目录,同时又将文件的访问路径向外导出(file-loader)
3.代码检查类型
- 对代码进行校验的加载器,目的是统一代码风格,提高代码质量
9、Webpack与ES2015
webpck只是打包工具,不会去处理ES6或者更高版本的新特性,如果需要处理,可以安装特定的加载器来完成。
加载器可以用来编译转换代码
10、Webpack模块加载方式
尽量不再要项目中混合使用这些标准,会降低项目可维护性,使用一个就可以了。
loader加载非js文件也会触发资源加载
几乎所有有引用资源的地方都会被webpack找出来,然后根据配置交给不同的loader处理,最后将处理的结果整体打包到输出目录,webpack就是通过这样的特点实现整个项目的模块化。
11、Webpack核心工作原理
Loader机制是Webpack的核心
打包核心工作过程
在项目中,都会散落着各种资源文件,webpack会根据配置找到其中一个,作为打包的入口。一般情况下这个文件都是js文件,然后会顺着入口文件的代码,根据代码中出现的import或require之类的语句,解析推断出这个文件所依赖的资源模块,然后分别去解析每一个资源模块对应的依赖,最后就形成了整个项目中所有文件依赖关系的依赖树,有了这个依赖树,webpack会递归这个依赖树,然后找到每个节点所对应的资源文件,最后在根据配置文件中的rules属性,去找到这个模块所对应的加载器,然后交给对应的加载器去加载这个模块,最后将加载到的结果放入到打包结果中,从而去实现整个项目的打包。
12、Webpack Loader工作原理
loader负责资源文件从输入到输出的转换,对于同一个资源可以依次使用多个loader处理,但是loader管道最后必须要返回一个js代码
13、Webpack 常用插件
1.自动清除目录插件
yarn add clean-webpack-plugin --dev
2.自动生成使用打包结果的HTML
yarn add html-webpack-plugin --dev
3.复制静态资源
yarn add copy-webpack-plugin --dev
14、Webpack 开发一个插件
webpack要求插件必须是一个函数或者是一个包含apply方法的对象,插件是通过在生命周期的钩子中挂载函数实现扩展
class MyPlugin {
apply (compiler) {
console.log('MyPlugin 启动')
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation => 可以理解为此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].source())
if (name.endsWith('.js')) {
const contents = compilation.assets[name].source()
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
compilation.assets[name] = {
source: () => withoutComments,
size: () => withoutComments.length
}
}
}
})
}
}
module.exports = {
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html
new HtmlWebpackPlugin({
title: 'Webpack Plugin Sample',
meta: {
viewport: 'width=device-width'
},
template: './src/index.html'
}),
// 用于生成 about.html
new HtmlWebpackPlugin({
filename: 'about.html'
}),
new CopyWebpackPlugin([
// 'public/**'
'public'
]),
new MyPlugin()//自己创建的插件
]
}
15、Webpack 自动编译
watch工作模式
监听文件变化,自动重新打包
yarn wabpack --watch //这样运行命令webpack会进行监听模式
16、Webpack 自动刷新浏览器
安装BrowserSync插件 弊端比较多
17、Webpack Dev Server
webpack提供用于开发的HTTP Server,集成了自动编译和自动刷新浏览器等功能,为了提高工作效率,dev-server并没有将打包结果写入到磁盘当中(暂时存在内存当中),内部的http server就是直接从内存当中读取这些文件,然后发送给浏览器,这样就能减少很多不必要到磁盘读写操作,大大提高构建效率。
yarn add webpack-dev-server --dev
静态资源访问
只要是通过webpack打包输出的文件,都可以正常被访问到,但是如果还有静态资源也需要作为开发服务器到资源被访问,那就需要额外的去告诉webpack dev-server。具体的方法,在webpack的配置当中去添加配置,配置devServer属性。
devServer: {
contentBase: './public',//contentBase可以是字符串或数组
},
contentBase能为开发服务器额外指定查找资源目录
代理API服务 不懂
18、Source Map(源代码地图)
用于映射源代码和转换后代码的关系,转换后的代码可以用Source Map逆向转换回源代码。主要是解决了源代码与运行代码不一致所产生的调试问题
19、Webpack 配置Source Map
webpack对source map的风格支持有12种,也就是有很多种实现方式,每种方式的效果和效率都是不同的,效果最好的,生成速度最慢,速度最快,生成的就没什么效果。
eval模式
构建最快,效果很简单,只能定位源代码的名称,而不知道具体的行列信息
20、Webpack devtool模式对比
inline-source-map
hidden-source-map
这个模式下,在开发工具下是看不到source map效果的,在开发第三方包比较有用,
nosource-source-map
这个模式能看到错误输入信息,但是点击进去看不到源代码的,表示没有源代码,但是提供了行列信息,这是为了在生成环境中保护源代码不被别人看到。
21、如何选择合适的Source Map
开发模式
常用cheap-module-eval-source-map模式
生产模式
不生成,因为会暴露源代码,因为调试是在开发阶段的事情,所以没必要在生成阶段还使用source map,如果一定要使用,可以使用nosource-source-map模式。
22、Webpack HMR(模块热替换)
热拔插
在一个运行的机器上随时插拔设备,而且机器的状态也不会受到插拔设备的影响,且插上的设备可以立即开始工作如生活中的USB接口
模块热替换
在程序运行中,实时替换某个模块,应用的运行状态也不会被改变,算是Webpack中最强大的特性之一,也是最受欢迎的特性。
使用
HMR集成在webpack-dev-server中不用再单独安装模块,只需要在运行webpack-dev-server这个命令时候在后面加上--hot就能开启这个特性,或者在配置文件配置。
实现所有模块热替换
样式文件可以直接热更新,而js文件不能,是因为js文件编码无规律,所以webpack无法处理更新后的模块, 所以无法现实现所有文件通用的替换方案,就需要手动处理js模块更新后的热替换。
通过脚手架创建的项目,内部都集成了HMR方案,所以不需要手动处理。
webpack中的HMR不是开箱即用的,还需要做一些操作,需要手动处理模块热替换逻辑,
JS模块热替换
图片模块热替换
个人理解
就是在开发者改变源代码,页面会刷新,然后在页面编辑的东西就会丢失掉,又要再一次写入,但是如果想加入新代码,状态数据不丢失,就要使用模块热替换。
23、Webpack使用HMR APIs
js文件是通过HMR的API来实现模块的热替换的,使用后就不会触发页面更新了。
因为每个文件的需要保留的状态不同,无法写出相同的替换逻辑,所以不同状态的js文件替换需要自己写出不同的替换逻辑
24、Webpack HMR注意事项
1.处理HMR的代码报错会导致自动刷新,使用hotOnly的方式来处理,处理后如果HMR代码报错,就不会自动刷新,就能快速定位到写错的地方。
2.没有启用HMR的情况下,HMR API报错
当使用HMR的API但是启动Dev Server的时候没有开启HMR的选项,此时就会报错,所以这是后要写判断,判断有这个对象,有才去使用
25、Webpack环境配置与优化
生产环境和开发环境有很大的差别,生产环境注重运行效率,开发环境注重开发效率,而在开发环境中我们为了让开发效率更高,会采用很多工具如Source Map和HMR等,这些工具都会往输出结果中添加额外的代码,这样就会让打包结果越来越臃肿。webpack建议为不同的工作环境创建不同的配置。
不同环境下的配置方式
- 配置文件根据环境不同导出不同配置,判断环境名参数这种方式只适合中小型项目
yarn webpack //不传入参数,webpack采用开发模式打包
yarn webpack --env production //传入参数production,采用生产模式打包
- 一个环境对应一个配置文件,大型项目建议使用的方式,这种情况下至少有三个配置文件,其中两个是用来适配不同环境的(开发和生产),另外一个是公共的配置。
首先建立webpack.common.js用于存放公共配置,webpack.dev.js用于存放开发环境配置,webpack.prod.js用于存放生产环境配置
下载webpack-merge用于与公共环境配置的合并
yarn add webpack-merge --dev
运行yarn webpack --config webpack.prod.js就能以生产环境的配置打包了
26、Webpack DefinePlugin(插件)
用于为全局注册成员
27、Webpack Tree-shaking(摇树)
用于摇掉代码中未引用掉部分(未引用代码dead-code),会自动检查未引用掉代码,让后将它们移除,去除冗余代码是生产环境非常重要的一个优化,Tree-shaking这个功能会在生产环境下自动开启。
使用
Tree-shaking不是webpack中的某一个配置选项,是一组功能搭配使用后的优化效果
28、Webpack 合并模块(concatenateModules)
作用就是,尽可能把所有的模块合并输出到一个函数中,这样既提升了工作效率,又减小了代码体积,这个特性又被称作为Scope Hoisting(作用域提升),是webpack3中添加的特性,配合minimize一起使用会让代码体积减小很多
29、Webpack Tree-shaking & Babel
很多书中说使用Tree-shaking会导致Babel-loader失效问题
首先Tree-shaking实现的前提是必须要使用ESModules来组织代码,相当于交给webpack的打包代码必须是ESM的方式来去实现的模块化。 webpack在打包前会先把模块根据配置,交给不同的loader处理,然后将所有loader处理的结果打包到一起,那么为了转化代码中的ESAScript新特性,会多时候都会使用babel-loader处理JS,而在babel转化代码时,就会可能处理掉ESModules把它们处理成CommonJS(取决于有没有使用转换ESM的插件),
结论
最新版本的Babel-loader不会导致Tree-shaking失效,因为babel-loader会帮我们自动关掉ESM转换的插件,如果实在不放心,也可以在webpack配置中手动去关掉ESM的转换。
30、Webpack sideEffects(副作用)
允许我们运用配置的方式来标记代码是否有副作用,从而为Tree-shaking提供更大的压缩空间。副作用:模块执行时除了导出成员之外做的事情。使用这个功能的前提是确保你的代码没有副作用
sideEffects一般用于npm包标记是否有副作用
场景
一个文件导出三个包,而此时你需要导入这个文件,使用这个文件中的一个包,但是打包后三个包都会在打包的结果中出现,想要的结果是,把两个没有使用的包去掉,这时候就可以使用sideEffects这个特性。在webpack中配置sideEffects是为了开启这个功能,在package中为了标识我们的代码没有副作用。
31、Webpack 代码分割(code splitting)
1.多个打包入口,同时打包,输出多个打包结果, 适用场景,多页应用程序,一个页面对应一个打包入口,公共的部分单独提取
提取公共模块
不同的入口肯定有公共模块
2.动态导入,实现模块的按需加载,节省带宽和流量。 动态导入的模块会被自动分包
32、Webpack 魔法注释
默认通过动态导入,产生的打包文件,名字只是一个序号,如果需要给打包文件命名,可以使用魔法注释
这样写后两个文件都会被打包到components的文件中,这样就要可以灵活的让动态加载的文件,到注定的打包位置了。
33、Webpack MiniCssExtractPlugin(提取css到单个文件)
css超过150kb才考虑提取到单个文件当中
yarn add mini-css-extract-plugin --dev
34、Webpack optimize-css-assets-webpack-plugin(压缩css文件)
34、Webpack 输出文件名Hash
在部署前端资源文件时,都会启用服务器的静态资源缓存,用户浏览器缓存静态资源后就不需要请求服务器得到这些静态资源,这样响应速度就会大幅度提升。
开启客户端资源缓存会带来新的问题,如果在缓存策略中,缓存失效的时间设置过长,在这个时间中应用发生更新,重新部署过后,没有办法及时更新到客户端,为了解决这个问题,在生产模式下,建议输出的文件名使用hash值,一旦资源文件发生改变,文件名称也会一起变化,对于客户端而言,全新的文件名就相当于全新的请求,就解决了上述问题。
支持hash的设置文件名的方式有三种
项目级别hash
chunkhash
contenthash文件级别hash(最适合用来解决缓存问题的)
hash一般为20为,也可以手动设计位数