webpack
webpack是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)
- 为啥要用webpack?
-
- 有效处理模块化。默认情况下,浏览器并不支持模块化,而我们的前端项目又使用了模块化,有了webpack之后,就可以突破这个限制了。
- webpack可以把多个相互引用的.js文件打包成一个文件,且文件有加密,压缩的效果,上线更安全。
- 这个过程中nodejs起了什么作用?
-
- 它是webpack的运行基础,没有了nodejs环境,就无法做类似于文件读写的操作了。
- 最终生成的main.js并不是在nodejs环境中运行的,整个的项目效果还是在浏览器中运行的。
安装使用webpack
命令:npm i webpack webpack-cli -D // --save-dev 它是一个开发依赖
可通过 npx webpack -v 查看安装是否成功(npx为npm5.2之后提供的新功能)
配置入口及出口
创建webpack.config.js,在里面添加配置项
默认只能打包js文件,打包其他类型,需下载各种loader加载器
// 引入nodejs中的核心模块
const path = require('path')
console.log(path.join(__dirname,'/build'))
module.exports = {
mode: "production",
entry: './src/js/main.js', // 入口文件
output: {
"path": path.join(__dirname,'/build'), // 决定出口文件在哪里
"filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
}
}
复制代码
-
mode 提供两种模式(不设置默认production)
development :开发模式(代码不会压缩 混淆) production:生产模式(压缩,混淆,加密....... 不可读)
-
entry 入口文件配置,可修改,路径一定要和打包的文件路径一致
-
output
path属性:可修改, 决定出口文件在哪里
filename:可修改,决定出口文件的名字
简化打包命令
可以在package.json中添加script命令来快速启动webpack
"scripts": {
"build": "webpack",
"test": "echo "Error: no test specified" && exit 1"
}
复制代码
配置好命令后就可以用 npm run build 或 yarn build来启动打包命令
之后需要打包其他类型文件,需要下载包,并在webpack.config.js中添加配置
loder
loader处理css文件
需要用到css-loader和style-loader,也都是开发依赖
命令: npm i style-loader css-loader -D 或 yarn add style-loader css-loader -D
module.exports = {
module:{ // 处理非js模块
rules:[ // 规则
{
test: /.css$/, // 正则测试,以.css结尾的文件
use: ['style-loader','css-loader'] // loader
}
]
}
}
复制代码
打包css需要两个包一起使用,在use属性里面,两者顺序不能交换,因为,在use数组中loader执行的顺序是从右到左的,即
- 先用css-loader来处理css
- 再用style-loader把css代码插入到html中的style标签中。
再次用打包即可看到效果
loader处理less文件
命令: npm i less-loader less -D
- less 用来把less-->css
- less-loader用来加载less文件
在rules再添加一个配置项
module.exports = {
module:{ // 处理非js模块
rules:[ // 规则
{
test: /.css$/, // 正则测试,以.css结尾的文件
use: ['style-loader','css-loader'] // loader
},
{
test: /.less$/, // 正则匹配,以.less结尾的文件
use: ['style-loader','css-loader','less-loader'] // 匹配成功,使用指定的loader
}
]
}
}
复制代码
注意:如上配置中,对于less文件的处理涉及三个loader,其处理顺序是less-loader --> css-loader-->style-loader。
- less-loader:用来加载less文件,并处理成css
- css-loader:用来加载css文件
- style-loader:用来将css代码以style标签的格式插入到html文件中
处理资源文件
处理图片资源时,在5.0版本以上是不需要再下载loader加载器的,直接配置即可
module.exports = {
module: {
rules: [
// ...省略其他
{
test: /.(png|jpg|gif|jpeg)$/i, // 匹配图片文件
type: 'asset' // 在导出一个 data URI 和一个单独的 文件之间自动选择
}
]
}
}
复制代码
会根据图片文件大小,自动选择是否使用base64格式的图片
另外webpack 还有很多loader 配置详情可参考 webpack中文网:webpack.docschina.org/
plugin
plugin是用于扩展webpack的功能,各种各样的plugin几乎可以让webpack做任何与构建相关关的事情。 plugin的配置很简单,plugins配置项接收一个数组,数组里的每一项都是一个要使用的plugin的实例,plugin需要的参数通过构造函数传入。
使用plugin的难点在于plugin本身的配置项,而不是如何在webpack中引入plugin,几乎所有webpack无法直接实现的功能,都能找到开源的plugin去解决,我们要做的就是去找更据自己的需要找出相应的plugin。
html-webpack-plugin
功能:把我们自已写的.html文件复制到指定打包出口目录下,并引入相关的资源代码。
为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题。可以生成创建html入口文件。
安装命令: npm i html-webpack-plugin -D
1.引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
复制代码
2.添加一个plugin配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
module: {
rules: [
// ...省略其他
{
test: /.(png|jpg|gif|jpeg)$/i, // 匹配图片文件
type: 'asset' // 在导出一个 data URI 和一个单独的 文件之间自动选择
}
]
},
plugins: [
new HtmlWebpackPlugin({ // 打包输出HTML
minify: { // 压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true// 压缩内联css
},
filename: 'index.html',
template: path.resolve('./index.html') // 指定模块的位置
})
]
}
复制代码
3.打包测试
- 它会把template中指定的.html文件复制(压缩)到出口文件夹
- 还会自动附上打包之后.css和 .js代码
clean-webpack-plugin
在生成打包文件之前,把目录清空掉。
命令:npm i clean-webpack-plugin -D
1.引入
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
复制代码
2.添加plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
module: {
rules: [
// ...省略其他
{
test: /.(png|jpg|gif|jpeg)$/i, // 匹配图片文件
type: 'asset' // 在导出一个 data URI 和一个单独的 文件之间自动选择
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({ // 打包输出HTML
minify: { // 压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true// 压缩内联css
},
filename: 'index.html',
template: path.resolve('./index.html') // 指定模块的位置
})
]
}
复制代码
webpack实时打包
实现实时打包预览效果。当我们修改了代码时,立即运行打包命令,并显示效果。
命令: npm i webpack-dev-server -D
配置文件
module.exports = {
// 其他省略....
// 配置 webpack-dev-server的选项
devServer: {
host: '127.0.0.1', // 配置启动ip地址
port: 10088, // 配置端口
open: true // 配置是否自动打开浏览器
}
}
复制代码
在package.json中补充一个script ,简化命令
"scripts": {
"serve": "webpack-dev-server", // 它默认会找webpack.config.js文件
},
复制代码
命令可修改,自己定义,配置完成后,执行npm run serve或 yarn serve即可实时浏览器查看效果
注意:浏览器看到的实时效果是服务器通过“**内存**”提供的,没有物理文件,也不会生成dist目录,待项目完成需手动打包上线
总结webpack常见问答
1、什么是webpack
- webpack是一个javascript的静态模块打包工具
- webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,增强功能
- 最后输出由多个模块组合成的文件,webpack专注构建模块化项目
2、webpack的优点是什么?
- 专注于处理模块化的项目,能做到开箱即用,一步到位
- 通过plugin扩展,完整好用又不失灵活
- 通过loaders扩展, 可以让webpack把所有类型的文件都解析打包
- 社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展
3、webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全
webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
- 初始化参数:从配置文件读取与合并参数,得出最终的参数
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,开始执行编译
- 确定入口:根据配置中的 entry 找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 webpack 提供的 API 改变 webpack 的运行结果
4、说一下 webpack 的热更新原理
webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS(webpack-dev-server) 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。
后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。
5、有哪些常见的Loader?他们是解决什么问题的?
1、 file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
2、 url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
3、 source-map-loader:加载额外的 Source Map 文件,以方便断点调试
4、 image-loader:加载并且压缩图片文件
5、 babel-loader:把 ES6 转换成 ES5
6、 css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
7、 style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
8、 eslint-loader:通过 ESLint 检查 JavaScript 代码
6、Loader和Plugin的不同?
1 不同的作用
loader直译为"加载器"。webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果。
2 不同的用法
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。