模块化打包工具的由来:ES Modules存在环境兼容问题、模块文件过多,网络请求频繁,而且所有的前端资源都需要模块化。
打包工具解决的是前端整体的模块化,并不单指JavaScript模块化
webpack:模块打包器、模块加载器、代码拆分、载入资源模块
一、webpack的基本使用
- 先在项目的根目录下执行
yarn init -y
,创建package.json - 安装webpack相关依赖:
yarn add webpack webpack-cli --dev
- 查看webpack版本:
yarn webpack --version
- 执行 yarn webpack 进行打包,生成了 dist 目录,里面有 main.js 文件
- 修改 index.html 中的index.js的路径为 dist/main.js ,并且去掉 script 标签的 type=module 的属性
- 去package.json的scripts中定义一个build任务:”build”: “webpack”, 以后执行yarn build进行打包
二、webpack的配置文件
webpack.config.js文件是运行在nodejs文件下的js文件,我们需要按照CommonJS的方式编写代码。这个文件需要导出一个对象,我们完成对应的配置选项。
webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js', // 指定打包入口文件,如果是相对路径,前面的点和斜线不能少
output: {
filename: 'bundle.js', // 输出文件的名称
path: path.join(__dirname, 'output'), // 输出路径,为绝对路径
}
}
三、webpack工作模式
直接执行webpack打包的时候,控制台会有警告,说没有指定工作模式,默认以生产模式打包,会进行代码的压缩。
我们可以通过cli命令指定工作模式,就是增加一个--mode
的参数,属性有三种选择,production、development、none
- production:生产模式会默认启动优化,优化我们的打包结果
- development:开发模式,会自动优化打包的速度,添加一些调试过程中的辅助到代码中
- none:原始状态的打包,不会做任何处理
可以通过yarn webpack —mode development来执行.
此外,还可以在webpack的配置文件中指定工作模式,也就是增加一个mode属性,例如:mode: “development”
四、webpack资源模块加载
将配置文件中的entry
属性的值改为./src/main.css
,然后执行打包命令yarn webpack
,会报错
因为webpack默认会把文件当做js解析,所以打包css文件时,文件内容不符合JS语法则报错了,报错中提示我们可以寻找正确的loader去解析代码。webpack内部的loader只能解析js,所以我们要手动安装css-loader去处理css代码。
loader是实现前端模块化的核心,通过它,可以加载任何类型的资源
执行命令:yarn add css-loader --dev
然后在webpack的配置文件中增加属性
module: {
rules: [
{
test: /.css$/,
use: 'css-loader'
}
]
}
增加外部的loader需要在配置文件中增加资源模块module属性,属性值是一个对象,对象中有一个rules数组,数组里每个元素都是一个对象,对象中的test属性是正则式,指明要处理的资源文件,use属性是对该资源进行处理的loader名称。
再次执行打包命令,发现css没有作用,是因为我们使用css-loader只是对css文件进行了打包,但是并没有作用到页面上,接下来还要安装一个style-loader
执行命令:yarn add style-loader --dev
style-loader是将css-loader处理后的结果,通过style的形式追加到页面上
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
}
use配置了多个loader,是一个数组,里面的loader是从右往左执行,所以要将css-loader写在后面,我们要先用css-loader将css代码转化成js模块,才可以正常打包。
五、webpack 导入资源模块
虽然webpack的入口文件可以是别的类型文件,但由于前端项目是由JS驱动,所以我们开发时一般将入口文件设置为JS文件,需要用到CSS时,就直接在JS文件中通过import导入即可,如:import ‘./main.css’
webpack建议我们根据代码的需要在JS中动态导入资源文件,因为需要资源的不是应用,而是代码。
因为是JavaScript驱动了整个前端应用,这样做的好处是:
- 逻辑合理,JS确实需要这些资源文件
- 确保上线资源不缺失,都是必要的
六、webpack文件资源加载器
安装文件资源加载器:yarn add file-loader --dev
,相当于直接拷贝物理文件。
不过此时资源文件路径会出现问题,webpack默认认为它打包过后的文件会放在网站的根目录下面,此时需要在配置文件中的output属性中指定publicPath属性值为dist/,即:publicPath: ‘dist/‘ ,这样在打包时,文件的输出路径前面会拼接上publicPath的值。
七、webpack URL 加载器
格式:协议 + 媒体类型和编码 + 文件内容
格式: data:[
例如:data:text/html;charset=UTF-8,
html content
先安装url-loader:
yarn add url-loader --dev
普通文件会转成Data URLs,图片会转成base64编码,会把文件的内容在打包后的文件在用data url的形式显示
修改png文件的loader为url-loader
{
test: /.png$/,
// use: 'file-loader',
use: 'url-loader'
}
执行yarn webpack
,此时的png文件的URL则为data协议的了。
最佳使用方式:
- 小文件使用Data URLs,减少请求次数
- 大文件独立提取存放,提高加载速度
配置方式:
{
test: /.png$/,
// use: 'file-loader',
use: {
loader: 'url-loader',
options: {
limit: 10 * 1024, // 单位是字节 10KB
}
}
}
- 超过10KB的文件单独提取存放
- 小于10KB文件转换为Data URLs嵌入代码中
注意:这种方式还是要安装
file-loader
,因为对超出大小的文件还是会调用file-loader
,如果没有file-loader会报错。
八、webpack 常用加载器分类
- 编译转换类,转换为JS代码,如
css-loader
- 文件操作类,将资源文件拷贝到输出目录,将文件访问路径向外导出,如:
file-loader
- 代码检查器,统一代码风格,提高代码质量,如:`es-loader``
`
九、webpack 处理ES2015
因为模块打包需要,它会处理import和export,除此之外,并不能转换其他的ES6特性。如果想要处理ES6,需要安装转化ES6的编译型loader。
最常用的就是babel-loader,babel-loader依赖于babel的核心模块,@babel/core和@babel/preset-env
执行命令:yarn add babel-loader @babel/core @babel/preset-env —dev
修改js的loader
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
exclude: /(node_modules)/, // 这里很重要,千万别忘了,否则会出错的。
}
十、webpack的模块加载方式
- 遵循ES Modules标准的import声明
- 遵循CommonJS标准的require函数。对于ES的默认导出,要通过require(‘./XXX’).default的形式获取
- 遵循AMD标准的define函数和require函数
- Loader加载的非JavaScript也会触发资源加载
样式代码中的@import指令和url函数
@import url(reset.css);
body {
margin: 0 auto;
padding: 0 20px;
max-width: 800px;
background: url(1.png);
background-size: cover;
}
css-loader在处理css代码时,遇到了background属性中的url函数,发现是引入的资源文件是png格式的文件,则将这个资源文件 交给url-loader处理
html-loader处理HTML文件中,加载其他资源,如:代码中的图片标签的src属性
{
test: /.html$/,
use: {
loader: 'html-loader',
options: {
//attrs:['img:src','a:href'],
// html-loader默认只处理页面中的img标签的src属性的资源文件,所以其他标签的资源文件要处理
attributes: {
list: [
{
tag: 'img',
attribute: 'src',
type: 'src'
},
{
tag: 'a',
attribute: 'href',
type: 'src'
}
]
}
}
}
}