这是我参与「第四届青训营 」笔记创作活动的第1天
什么是Webpack
本质上是一种前端资源编译、打包工具
- 多份资源文件打包成一个Bundle
- 支持Babel、Eslint、TS、Less、Sass
- 支持模块化处理css,图片等资源文件
- 支持持续监听、持续构建
- 支持代码分离
一、webpack使用
初始化配置
- 安装
npm i -D webpack webpack-cli - 编辑配置文件 webpack.config.js
- 执行编译命令
npx webpack
编译打包应用
- 运行指令
- 开发环境指令:
webpack src/js/index.js -o build/js/built.js --mode=development
功能:打包编译js和json文件,并且能够将es6的模块化语法转换为浏览器能识别的语法
- 生产环境指令
webpack src/js/index.js -o bulid/js/built.js --mode=production
功能:在开发配置功能上压缩代码
- webpack工作流程
- 入口处理:从
entry文件开始,启动编译流程 - 依赖解析,从
entry文件开始,根据requireorimport等语句找到依赖资源 - 资源解析,根据
module配置,调用资源转移器,将png、css等非标准js资源转义为js内容 - 递归2,3,知道所有资源处理完成
- 资源合并打包,将转译后的资源内容合并打包为可直接在浏览器运行的js文件
- 总结
- webpack能处理js/json,不能处理css/img等其他资源
- 生产环境和开发环境将ES6模块化编译成浏览器能识别的module
二、webpack开发环境的基本配置
- 创建配置文件
/*
webpack.config.js webpack配置文件
作用:指示webpack干哪些活(当运行 webpack 指令时,会加载里面的配置)
所有构件工具都是基于nodejs平台运行的,模块化默认采用commonjs(配置,项目src的使用es6的import)
*/
const { resolve } = require('path') //resolve:处理绝对路径的方法
module.exports = {
//webpack配置
//=========== 1. 入口起点
entry:'./src/index.js',
//=========== 2. 输出
output:{
filename:'built.js', //输出文件名
//__dirname是nodejs的一个变量,代表当前文件(webpack.config.js)的目录绝对路径
path:resolve(__dirname,'build'), //输出路径,
},
//=========== 3. load的配置
module:{
rules:[
//详细的loader配置
]
},
//=========== 4.plugins的配置
plugins:[
//详细的plugins配置
],
//=========== 5.mode 模式
mode:'development',
// mode:'production'
}
- 打包样式资源
- 安装loader
npm add -D css-loader style-loader - 安装'module'处理css文件
const path=require('path')
module.exports={
entry:'./src/index',
output:{
filename:'[name].js',
path:path.join(__dirname,'./dist'),
},
module:{
rules:[
//详细的loader配置 (不同的文件必须配置不同的loader处理)
{
//匹配哪些文件 --- 使用正则
test: /\.css$/,
//使用哪些loader进行处理
use: [ //use数组中的loader执行顺序:从右到左,从下到上
'style-loader', //创建style标签,将js中的css样式资源插入进去,添加到head中生效
'css-loader' //将css文件编程commonjs模块加载到js中,里面的内容是样式字符串
]
}],
}
}
- css文件在js中的引用
const styles=require('./index.css');
// or
import styles from './index.css'
- 生成HTML资源
- 安装依赖
npm i -D html-webpack-plugin - 声明产物出口'output'
/*
loader: 1.下载 2.使用(配置loader)
plugins: 1.下载 2. 引入 3.使用
*/
const { path } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:'./src/index.js',
output:{
filename:'[name].js',
path:path.join(__dirname,'./dist'),
},
plugins:[
//html-webpack-plugin
//功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(js/css)
//需求:需要有结构的HTML文件,引入template配置
new HtmlWebpackPlugin({
template:'./src/index.html' //复制./src/index.html
})
],
mode: 'development'
}
- 打包图片资源
- 安装对应的loader
npm i -D url-loader - 如果直接在index.html中通过img引入图片,那么打包后html中模板还是index.html内容。也就是src中的图片路径不变,但是打包后的图片文件命名都是hash值,根本获取不到图片。所以需要使用html-loader处理html文件的img图片
module:{
rules:[
{...},
{
//问题:默认处理不了html中img图片
//处理图片资源
test:/\.(jpg|png|gif)$/,
//只有一个loader可以不使用user[]格式,这里需要下载url-loader和file-loader
loader:'url-loader',
options:{
//图片大小小于8kb,就会被base64处理 --- 小图片处理(变成一串编码很长的字符串)
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积会更大(文件请求速度变慢)
limit: 8*1024,
/*
问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
解析时会出问题: 打包的html中img的url变成 [object module]
解决: 关闭url-loader的es6模块,使用commonjs解析 --- esModule:false
但是:在新版本的html-loader中这个问题已经被修复了,所以不关闭es6模块解析也没问题
*/
esModule:false,
//给图片重命名(原本默认打包后的图片命名是长串的hash值)
//[hash:10]取图片的hash的前10位,[ext]取原来文件的扩展名
name:'[hash:10].[ext]'
}
},
{
test: /\.html$/,
loader: 'html-loader' //处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
}
]
},
三、Loader
Webpack Loader只是实现内容转换器-将各式各样的资源转换为标注js内容格式。
css-loader将 css 转换为__WEBPACK_DEFAULT_EXPORT__ = ".a{ xxx }"格式html-loader将 html 转换为__WEBPACK_DEFAULT_EXPORT__ = "<!DOCTYPE xxx"格式vue-loader更复杂一些,会将.vue文件转化为多个 JavaScript 函数,分别对应 template、js、css、custom block
?为什么要使用loader?
webpack只认识符合js规范的文本:在构建make阶段,解析模块内容时会调用acorn将文本转换为AST对象,进而分析代码结构,分析模块依赖;这时候对图片、json、Vue SFC等场景不work了,就需要Loader介入将资源转化为Webpack可以理解的内容形式
Loader编写
module.exports=function(source,sourceMap?,data?){
return source;
}
Loader 函数接收三个参数,分别为:
source:资源输入,对于第一个执行的 loader 为资源文件的内容;后续执行的 loader 则为前一个 loader 的执行结果sourceMap: 可选参数,代码的 sourcemap 结构data: 可选参数,其它需要在 Loader 链中传递的信息,比如 posthtml/posthtml-loader 就会通过这个参数传递参数的 AST 对象
Loader链式调用
使用上,可以为某种资源文件配置多个 Loader,Loader 之间按照配置的顺序从前到后(pitch),再从后到前依次执行,从而形成一套内容转译工作流,例如对于下面的配置:
module.exports = {\
module: {\
rules: [\
{\
test: /\.less$/i,\
use: [\
"style-loader",\
"css-loader",\
"less-loader",\
],\
},\
],\
},\
};
less-loader:实现 less => css 的转换,输出 css 内容,无法被直接应用在 Webpack 体系下css-loader:将 css 内容包装成类似module.exports = "${css}"的内容,包装后的内容符合 JavaScript 语法style-loader:做的事情非常简单,就是将 css 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签
链式调用好处:一是保持单个 Loader 的单一职责,一定程度上降低代码的复杂度;二是细粒度的功能能够被组装成复杂而灵活的处理链条,提升单个 Loader 的可复用性。