Webpack笔记
从使用 webpack 的角度来说,搞清楚 webpack 的配置即可
安装
需要 node 14+ 和 npm(安装 node 时自动安装)。
全局安装
npm install webpack webpack-cli -g
局部安装(推荐)
npm init -y
-D 表示安装的开发依赖。加不加并不影响,但是推荐加,这样项目 package.json 会整洁些。
npm install webpack webpack-cli -D
基本使用
在新建项目的时候使用 webpack
打包会默认使用全局安装的 webpack,显然这可能导致兼容性的问题。一般来说,对于一个新项目,我们还是使用上面的局部安装方式自行安装一个 webpack。但是安装完再使用 webpack
进行打包还是会使用全局的 webpack,解决方法有两个:
- 使用
npx ./node_modules/webpack
手动执行当前目录下安装的 webpack - 在
package.json
中的script
部分,加上一个自定义的指令,如build
,内容为webpack
,然后使用npm run build
打包。(推荐)
{
"name": "01.basic_webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack" // 看这里
},
"keywords": [],
"author": "",
"license": "ISC"
}
配置入口/输入文件路径
webpack 的默认入口文件为 ./src/index.js
,输出文件为 ./dist
,可以在执行 webpack 的时候,使用 --entry xxx
指定入口文件路径,--output-path
指定输入文件配置。
npx webpack --entry ./src/main.js --output-path ./build
我们可以在 package.json
中配置这样的指令,更好的解决方式是使用 webpack 的配置文件。
webpack 配置文件(webpack.config.js)
同 npm 的 package.json
一样,webpack 也有一个配置文件,一般在项目根目录,取名 webpack.config.js
,内容如下:
// webpack.config.js
// 只能使用 CommonJS 的导出方法,因为 webpack 运行在 node 中
// 用 path.resolve 拼接路径
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
// 这里只能填绝对路径
path: path.resolve(__dirname, "build"),
filename: 'bundle.js'
}
}
webpack依赖图
假设有一个 element.js
用于给元素设置些样式,但是这个 js 文件没有被任何其他 js 文件引入,那么 webpack 打包的时候就不会把这个 js 打包。
解决方法:在 index.js
或者其他被 index.js
import 的 js 文件中 import "element.js"
webpack 打包 css
注意,最新版 webpack 的 rules 外面要套一层 module 属性,具体见下方代码
注意,rules 的 loaders 数组的加载顺序是从后往前的,所以如果一个 loader 依赖另一个 loader,被依赖的 loader 要在依赖loader 的后面
默认情况下 webpack 只能打包 js,如果用类似 import xx.css
导入 css,会报错。这时需要配置 css-loader,示例配置如下:
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader' // 需要事先安装 css-loader
}
]
}
]
}
}
可以看到我们在 webpack.config.js
中新增了一个 rules
字段,这个字段的值是一个对象数组,下面来详解 rules
的写法:
rules 的元素由 obj 构成,obj 的构成一般是
- test 文件名匹配正则表达式
- loader test 匹配成功后,使用的 loader
- use test 匹配成功后,使用的 loaders
rules: [
{
// test 的值是一个正则表达式,符合正则表达式的文件会使用 use 或者 loader 的规则进行打包
test: /\.ts$/,
// loader 语法糖形式,适合只需要一个 loader 的情况
// loader: 'typescript-loader'
// 多个 loader
use: [
{
loader: 'typescript-loader'
}
]
},
{
test: /\.css$/,
loader: 'css-loader'
},
{
test: /\.less/,
loader: 'less-loader'
}
]
配合使用 postcss
postcss 是什么?
postcss 是一个 css 优化工具,可以实现对 css 的 polyfill 等功能。
安装 postcss 和 postcss-loader
npm install postcss postcss-cli postcss-loader -D
在 webpack 中配置 postcss
再次手写 webpack.config.js
,权当复习 webpack 的配置写法。
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
// postcss 有个 postcssOptions
// 在 postcssOptions 中配置 plugins
postcssOptions: {
plugins: [
// autoprefixer: 自动给样式添加浏览器前缀
require('autoprefixer')
]
}
}
}
]
}
]
}
}
或者用配置文件的写法
这里思路实际和 webpack 的配置文件类似:
在项目根目录创建一个 postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
然后在 webpack.config.js
中,只用写 postcss-loader
而不用写配置。
配置文件的原理
很简单,加载 postcss 的时候,如果发现没有配置对象,那么就从 postcss.cofing.js
中读取导出对象,并作为 postcssOptions
传入。
配置补充
module.exports = {
mode: 'production | deveploment',
devtool: 'source-map'
}
- mode 指定 webpack 的优化程度
- devtool 设置为 source-map 方便开发中调试代码
练习
- 配置 less
- 配置 postcss 并安装 postcss-preset-env
- 使用单独的 postcss 配置文件 和 webpack 配置文件
webpack 资源
file-loader 打包图片
安装
npm install file-loader -D
使用
基本和打包 css 一样,看代码:
module.exports = {
module: {
rules: [
// 打包图片
test: /\.(jpe?g|png|svg|gif)/,
loader: 'file-loader'
]
}
}
在 css 中引入的时候,写法不变:
.bg {
background: url("../img/1.jpg");
}
打包好的图片会被 hash 命名移动到输出文件夹里,webpack 会自动修改引入名。
在 js 中引入的时候,需要使用 require
或者 import
导入图片:
const div = document.createElement('div');
div.style.backgroundImage = require('../img/1.jpeg');
file-loader 的 placeholder 配置
rules: [
{
// 打包图片
test: /\.(jpe?g|png|svg|gif)$/,
use: {
loader: 'file-loader',
options: {
name: 'img/[name]_[hash:6].[ext]'
}
}
}
]
webpack5 asset 代替 file-loader/url-loader
module.exports = {
module: {
rules: [
{
test: /\.jpg$/,
// 最常用的一种 type,可以自定义打包的大小阈值
type: 'asset',
generator: {
// 不同于 file-loader 的 placeholder,这里的 [ext] 自带 .
// 也就是无需再给文件名加 .
filename: 'img/[name]_[hash:6][ext]'
},
parser: {
dataUrlCondition: {
// 文件没有超过 100KB,则打包成 base64
maxSize: 100 * 1024
}
}
}
]
}
}
新增:
- type
- parser -> dataUrlCondition
- generator 指定保存文件名
webpack 插件
基本使用
webpack 的插件放置在配置文件的 plugins
属性里,我们可以下载需要的插件,在配置文件中导入,然后添加到 plugins
数组中。
插件的命名一般是 xxx-webpack-plugin
其中 xxx
是插件实现的功能名。使用 require
导入插件,并没有统一的规范,有的插件需要结构得到配置类,有的不需要,具体可以查[官方文档](HtmlWebpackPlugin | webpack)
例子:
- CleanWebpackPlugin 每次打包的时候自动删除上一次打包生成的文件
- HtmlWebpackPlugin 提供一个 html 模板,生成的模板会在
dist
这类输出文件夹里。可以在模板中书写 EJS 表示,然后传入一些配置。 - CopyWebpackPlugin 复制文件到指定
dist
输出文件夹 - DefinePlugin webpack 官方集成的数据定义插件,可以传入 BASE_URL 等自定义数据。
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('Html-webpack-plugin');
const { CopyWebpackPlugin } = require('copy-webpack-plugin');
const DefinePlugin = require('webpack');
module.exports = {
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
title: 'Vue app'
}),
new DefinePlugin({
// 这里传入的字符串会被当成变量名寻找,如果不想这样就需要传入一个字符串常量
BASE_URL: "'./'"
}),
new CopyWebpackPlugin()
]
}
webpack 热替换HMR
首先讲下什么是 HMR 以及它和 live loading 的区别。
HMR 即模块热替换,当某个模块发生更新的时候,只有这个模块会被更新,而页面其它状态不会被更新。这也是 HMR 和 Live Loading 的区别——Live Loading是无脑刷新网页,不能保存网页状态,且更新代价比 HMR 大。
基本使用
-
安装 webpack-dev-server
npm install webpack-dev-server -D
-
配置
package.json
// ... scripts: { "serve": "webpack serve" }
-
启动
npm run serve
devServer 的简单配置
在 webpack.config.js 中,添加两个属性:
module.exports = {
// ...
target: "web" // 配置 webpack 的打包目标
devServer: {
hot: true, // 启动 HMR;如果为 false 则是 live loading
contentBase: "./public", // webpack 没有打包的资源从这里找 如果有就用,没有才404,
host: "127.0.0.1",
port: 6767,
open: true, // 是否自动打开浏览器
compress: true // 是否开启 gzip 压缩
}
}
本地开发解决跨域问题
同样的,在 devServer
属性中配置:
module.exports = {
// ...
target: "web" // 配置 webpack 的打包目标
devServer: {
proxy: {
// 假设这里后端接口在 8899 端口,前端在 8888 端口
// 那么请求 /api 的时候,理想情况是请求 http://localhost:8899
// 但是这样配置还不能解决问题,因为 /api 会被重写成
// http://localhost:8899/api/xxx 因此需要配置重写设置
// "/api": "http://localhost:8899"
// 解决方案:/api 传入多个属性设置
"/api": {
// target 就是我们想访问的后端地址
target: "http://localhost:8899",
pathRewrite: {
// 以 /api 开头的请求会被重写为 ""
"^/api": ""
},
// 默认情况下为 true,即不代理到 https
// 设为 false 即可解决上述问题
secure: false,
//
changeOrigin: true
}
}
}
}
Vite 笔记
了解完 webpack 后,我们来了解下 vite。vite 也是一个前端的构建工具,相比 webpack 它更加轻量,速度更快,且配置更少。vite 对 vue 提供首要支持,所以可以很轻松的创建 vue 项目。
安装
npm install vite
简单使用
创建一个前端项目,目录结构如下:
index.html
src
main.js
js
app.js
css
style.css
其中,main.js
中实现一些功能,同时因为需要打包 css 所以要使用 import ./css/style.css
导入css。然后执行 npx vite
找到 node_modules/.bin/vite
运行 vite,看到提示后点击链接即可看到效果。导入 css 并不需要配置 loader。(main.js 需要用 module 模式引入)
导入 .less
文件时,需要安装 less;导入 .ts
文件时,无需执行任何配置;导入 .vue
文件时,需要安装 vite/plugin-vue
和 @vue/sfc-compiler
。然后创建 vite.config.js
写入如下内容:
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [vue()]
}
vite 的原理
vite1 使用 koa 作为后端语言,vite2使用 Connect 作为后端语言,这里用 vite2 举例。
当我们执行 npx vite
的时候,实际是启动了一个后端服务程序,浏览器访问资源的时候访问的就是导入的资源原文件,比如 style.less
,这些请求被 Connect 接受,然后 304 跳转到编译成 style.css
的文件中。可以理解为 Connect 的主要作用就是转发浏览器无法解析的文件的请求。
vite 创建 vueapp
1. 安装 create-app
npm install @vitejs/create-app
1.1 执行
create-app
然后按提示操作即可。
1.2 create-app 的替代方案
npm init vite
功能和上面一样。
2.安装依赖
create-app 之后实际上只是生成了项目结构,使用npm install
安装依赖,创建app。
3. 运行 & 打包
npm run dev
npm run build