- Entry : 入口,执行构建的第一步
- Module : 会从配置的Entry开始递归找出所有依赖的模块
- Chunk :用于代码的分割与合并
- Loader:模块转换器
- Plugin:扩展插件,在特定时机注入扩展逻辑改变构建结果
- Output:输出结果
webpack是对jacascript打包的工具,不能识别其他的文件,所以需要配置loader进行识别
前言 项目目录结构├─build │ ├─webpack.base.conf.js //开发环境和生产环境都有的操作配置文件 │ ├─webpack.dev.conf.js //开发环境配置文件 │ ├─webpack.prod.conf.js //生产环境配置文件 │ ├─webpack.rules.conf.js //模块匹配规则 ├─node_modules //依赖文件 ├─public //静态文件存储位置 | |-index.html //项目模板文件 └─src | ├─plugins | ├─router | ├─store | ├─views | |-App.vue | |-main.ts | |-shims-vue.d.ts |-.env.dev //环境文件 |-.env.test |-.env.prod |-.gitigore |-babel.config.js //bable配置文件 |-package.json |-postcss.config.js //适配规则 |-tsconfig.json1. 第一步初始化项目
yarn init -y 初始化项目 //-y是都回答yes 一键初始化2. 第二步安装webpack三件套
// 安装webpack三件套 yarn add webpack webpack-cli webpack-dev-server -D // -D 等价于--save-dev开发环境时的依赖 // -S 等价于--save生产环境时的依赖 //使用http://localhost:8080/webpack-dev-server/可以访问webpack-dev-server命令在 内存中生成的文件3. 创建配置文件,分功能创建
├─build │ ├─webpack.base.conf.js //公共配置 │ ├─webpack.dev.conf.js //mode为development配置 │ ├─webpack.prod.conf.js //mode为production配置 │ ├─webpack.rules.conf.js //loader配置3.1 创建src文件夹,并在里面创建main.js文件 3.2书写入口路径和输出路径
//webpack.base.conf.js
const path = require("path")
module.exports = function (proMode) {
return {
// JavaScript 执行入口文件
entry: path.resolve(__dirname, "../src/main.ts"),
output: {
// 输出文件都放到 dist 目录下
path: path.resolve(__dirname, "../dist"),
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: "./js/[name].[chunkhash].js",
// publicPath: "./",//生产环境时使用
clean: true
},
}
}
4 创建环境文件
.env.dev .env.test .env.prod4.1 书写环境内容
//.env.dev NODE_ENV="development" VUE_APP_BASE_API="/api" VUE_APP_API_USER="/user" VUE_APP_SHOWCONSOLE=true4.2 配置环境变量
//Dotenv是一个零依赖模块,它将环境变量中的变量从.env文件加载到process.env中
// 安装dotenv
yarn add dotenv -D
yarn add cross-env -D
//webpack.base.conf.js
const webpack = require("webpack")
const envMode = process.env.envMode
require("dotenv").config({
path: `.env.${envMode}`
})
const prefixRE = /^VUE_APP_/
let env = {}
for (const key in process.env) {
if (key == "NODE_ENV" || key == "BASE_URL" || prefixRE.test(key)) {
env[key] = JSON.stringify(process.env[key])
}
}
module.exports = function (proMode) {
return {
plugins: [
new webpack.DefinePlugin({ // 定义环境和变量
'process.env': {
...env
}
}),
],
}
}
4.3 修改package.json启动命令
"scripts": {
"dev": "cross-env envMode=dev webpack serve --config ./build/webpack.dev.conf.js --color",
"build": "cross-env envMode=prod webpack --config build/webpack.prod.conf.js --color",
"build:test": "cross-env envMode=test webpack --config build/webpack.prod.conf.js --color"
},
- cross-env:运行跨平台设置和使用环境变量的脚本
- –config:使用哪个配置文件
- –color :开启控制台颜色
//安装babel yarn add @babel/core @babel/preset-env babel-loader -D yarn add core-js -S5.1 匹配js进行转换
//webpack.rules.conf.js
module.exports = function (proMode) {
return [{
test: /.(t|j)s$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
},
]
}
5.2 安装TypeScript并使用babel进行转换
//安装ts yarn add typescript -D // 解析 typescript 的 babel 预 yarn add @babel/preset-typescript -D //polyfill 箭头函数 yarn add @babel/plugin-transform-runtime -D //支持 ts 类的写法 yarn add @babel/plugin-proposal-class-properties -D //支持三点展开符 yarn add @babel/plugin-proposal-object-rest-spread -D yarn add @babel/runtime @babel/runtime-corejs3 core-js -S5.3 创建babel.config.js
const presets = [
[
"@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": "3.19.1"
}
],
[
'@babel/preset-typescript', // 引用Typescript插件
{
allExtensions: true, // 支持所有文件扩展名,否则在vue文件中使用ts会报错
},
],
]
const plugins = [
//按需引入vant组件
[
"import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}, "vant"
],
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
},
],
'@babel/proposal-class-properties',
'@babel/proposal-object-rest-spread',
]
module.exports = {
plugins,
presets
}
6 自动生成HTML文件
yarn add html-webpack-plugin -D6.1 html-webpack-plugin配置
//webpack.base.conf.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const cdn = {
dev: {
css: [],
js: []
},
prod: {
css: [],
js: [
'https://lib.baomitu.com/vue/3.0.11/vue.runtime.global.prod.js',
"https://lib.baomitu.com/vue-router/4.0.6/vue-router.global.prod.min.js",
"https://lib.baomitu.com/vuex/4.0.0/vuex.global.prod.min.js"
]
}
}
module.exports = function (proMode) {
return {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"), //引用模板位置
filename: "index.html", //生成的html,路径相对于output.path
title: "webpack+vue3",
minify: {
collapseWhitespace: true, //是否折叠空白
preserveLineBreaks: false,
minifyCSS: true, //是否压缩
minifyJS: true,
removeComments: false
},
files: proMode ? cdn.prod : cdn.dev
}),
],
}
}
6.2 创建public文件夹,在里面创建index.html
// public/index.html //需将模板中的7 添加css支持和less支持标签里的内容改成 <%= htmlWebpackPlugin.options.title %> //CDN引入js <% for (var i in htmlWebpackPlugin.options.files&&htmlWebpackPlugin.options.files.js) { %> <% } %>
//css-loader提取.css的内容 //style-loader把.css的内容按照javascript中的字符串存储起来,在网页执行javascript时通过DOM操作动态的往HTML HEAD标签里插入style标签 yarn add style-loader css-loader -D yarn add less less-loader -D yarn add autoprefixer postcss-loader -D7.1 使用loader配置
//webpack.rules.conf.js
module.exports = function (proMode) {
return [
{
test: /.less/,
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
ident: "postcss",
plugin: () => {
require("postcss-preset-env")()
}
}
}
}, "less-loader"
]
},
{
test: /.css$/,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
ident: "postcss",
plugin: () => {
require("postcss-preset-env")()
}
}
}
},
// "less-loader"
]
}
]
}
loader从后往前执行
8. 配置alias别名和扩展名//webpack.base.conf.js
resolve: {
alias: {
"@": path.resolve(__dirname, "../src")
},
//扩展名书写
//把项目中所有的扩展名都写上去,要不然会报错
extensions: [".js", ".vue", ".ts"]
},
8.1 resolveLoader
//配置loader的解析规则
resolveLoader:{
//loader的寻找目录
modules:[
'node_modules',
]
}
9. 打包时清除上次构建dist目录
//webpack.base.conf.js
output: {
clean: true
},
10 识别.vue文件
yarn add vue-loader@next @vue/compiler-sfc -D yarn add vue@next -S
- vue-loader:解析转换.vue文件,提取出js/style/html模板
- @vue/compiler-sfc,vue-loader调用它对文件内容转换成webpack模块化的import形式,转换成AST抽象语法树
// webpack.rules.conf.js
rules: [
{
test: /.vue$/,
use: [
'vue-loader'
]
}
]
//webpack.base.conf.js
const { VueLoaderPlugin } = require('vue-loader/dist/index');
plugins: [
new VueLoaderPlugin()
]
10.2 添加App.vue
10.3 修改main.ts
import { createApp } from 'vue' // Vue 3.x 引入 vue 的形式
import App from './App.vue' // 引入 APP 页面组建
const app = createApp(App) // 通过 createApp 初始化 app
app.mount('#app') // 将页面挂载到 root 节点
10.4 创建vue类型声明文件
src/shims-vue.d.ts
declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
10.5 .vue文件一直报错,声明文件没生效
//tsconfig.js //includes把声明文件的路径加上,就不会了报错了 "types": ["./src/shims-vue.d.ts"],11. 安装vue全家桶
yarn add vue-router@4 vuex@next axios -S12. 集成Vant
yarn add vant@next -S
//按需引入
yarn add babel-plugin-import -D
// babel.config.js
const plugins = [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
//在搭建脚手架的同时,要区分css文件和less文件
//vant组件不能使用less-loader去识别,会报错
13. 识别图片
//webpack.conf.rules.js
module.exports = function (proMode) {
return [
{
test: /.(png|jpg|svg|gif)$/,
type: "asset/resource",
generator: {
filename: "assets/[hash:8].[name][ext]"
}
},
]
}
优化
1.静态文件输出到打包目录下
//使用copy-webpack-plugin插件时 ,要复制的文件夹里不能为空,否则报错
yarn add copy-webpack-plugin -D
//webpack.prod.conf.js
const copyWebpackPlugin = require("copy-webpack-plugin");
const webpackConfigProd = {
mode: "production",
plugins: [
new copyWebpackPlugin({
patterns: [{
from: path.resolve(__dirname, "../public"),
to: "./",
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/index.html"],
}
}]
}),
],
}
2. 提取样式文件
yarn add mini-css-extract-plugin -D
//webpack.base.conf.js
const miniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = function (proMode) {
return {
plugins: [
new miniCssExtractPlugin({
filename: "./css/[name].[contenthash].css",
}),
],
}
}
//webpack.rules.conf.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = function (proMode) {
return [
{
test: /.less/,
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
ident: "postcss",
plugin: () => {
require("postcss-preset-env")()
}
}
}
}, "less-loader"
]
},
{
test: /.css$/,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
ident: "postcss",
plugin: () => {
require("postcss-preset-env")()
}
}
}
},
// "less-loader"
]
}
]
}
3. vw适配
yarn add postcss-loader postcss-px-to-viewport -D
//新建postcss.config.js文件
const path = require("path")
module.exports = ({
file
}) => {
const designWidth = file.includes(path.join("node_modules", "vant")) ? 375 : 750;
return {
plugins: {
autoprefixer: {
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8"
]
},
"postcss-px-to-viewport": {
unitToConvert: 'px', // 需要转换的单位,默认为"px"
viewportWidth: designWidth, // 设计稿的视口宽度
unitPrecision: 5, // 单位转换后保留的精度
propList: ['*'], // 能转化为vw的属性列表
viewportUnit: 'vw', // 希望使用的视口单位
fontViewportUnit: 'vw', // 字体使用的视口单位
selectorBlackList: ['.ignore', '.hairlines', '.ig-'], // 需要忽略的CSS选择器
minPixelValue: 1, // 最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换,例如只转换 'src/mobile' 下的文件 (include: //src/mobile//)
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw', // 横屏时使用的单位
landscapeWidth: 568 // 横屏时使用的视口宽度
}
}
}
}
4. 生产环境去掉console 字体改成蓝色了
//webpack.prod.conf.js
const TerserPlugin = require('terser-webpack-plugin');
const webpackConfigProd = {
mode: "production",
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
extractComments: false,
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}),
]
}
}
5. 缓存
//webpack.base.conf.js
module.exports = function (proMode) {
return {
cache: {
type: "filesystem",
buildDependencies: {
config: [__filename]
}
},
}
}
tapable
1.如何使用
初始化容器
注册事件
触发容器
2. complier 插件/plugin是构造函数或者是类
compilation在调用complier时会相应调用
初始化compilation钩子
添加资源
自定义webpack 1.定义一个函数,返回值为一个compiler类 2.编写compiler类 初始化配置
获取入口地址
读取入口文件内容
通过@babel/parser将其内容转换为抽象树
通过@babel/traverse收集依赖
如果当前文件有依赖
获取文件路径,生成绝对路径
同时添加到依赖数组中
编译代码,将代码中浏览器不能识别的语法进行编译
3.遍历所有依赖 4. 生成bundle定义bundle字符串获取code内容
获取文件绝对路径
把这个代码写入文件里



