Webpack 基础
Webpack 基础
基本使用
webpack
是一个静态资源打包工具。
它会将一个或者多个文件作为打包的入口,将我们整个项目所有文件编译组合成一个或者多个文件输出出去。
输出的文件就是编译好的文件,就可以在浏览器端运行。
我们将webpack
输出的文件叫做bundle
。
功能介绍
webpack本身功能是有限的:
- 开发模式:仅能编译JS中的
ES Module
语法。 - 生产模式:能编译JS中的
ES Module
语法,还能压缩JS代码。
开始使用
1.资源目录
webpack_code # 项目根目录(所有指令必须在这个目录中运行)
└── src # 项目源码目录
|──js # js目录
| |—— count.js
| └── sum.js
└── main.js # 项目主文件
2.创建文件
- count.js
export default function count(x,y){
return x + y;
}
- sum.js
export default function sum(...args){
return args.reduce((pre,cur)=> pre + cur,0)
}
- main.js
import count from "./js/count"
import sum form "./js/sum"
console.log(count(2,1))
console.log(count(1,2,3,4,5))
3.下载依赖
打开终端,在项目根目录下执行指令
- 初始化``package.json
npm init -y
- 下载依赖
npm i webpack webpack-cli -D
4.启用webpack
- 开发模式
npx webpack ./src/main.js --mode=development
- 生产模式
npx webpack ./src/main.js --mode=production
npx webpack
:是用来运行本地安装webpack
包的。
./src/main.js
:指定webpack
从main.js
文件开始打包,不但会打包main.js
,还会将其他依赖也一起打包进来。
--mode=production
:指定模式(环境)。
5.观察输出文件
默认webpack
会将文件打包输出到dist
目录下。
webpack
本身功能比较少,只能处理js
资源,一旦遇到css
等其他资源就会报错。
所有我们学习webpack
,就是主要学习如何处理其他资源。
基本配置
在开始使用webpack
之前,我们需要对webpack
的配置有一定的认识。
五大核心概念
- entry(入口)
指示 webpack 从哪个文件开始打包。
- output(输出)
指示 webpack 打包完的文件输出到哪里去,如何命名。
- loader(加载器)
webpack 本身只能处理js、json等资源,其他资源需要借助loader,webpack 才能解析。
- plugins(插件)
扩展 webpack 功能。
- mode(模式)
主要有两种开发模式:
- 开发模式:development
- 生产模式:producton
webpack 配置文件
webpack.config.js
const path = require("path")
module.exports = {
//入口
entry: "./src/main.js",
// 输出
output: {
// 文件的输出路径
path: path.resolve(__dirname, "dist"),
filename: "main.js"
},
// 加载器
module: {
rules: []
},
// 插件
plugins: [],
// 模式
mode: "development"
}
开发模式
开发模式顾名思义就是我们开发代码时使用的模式。
这个模式下我们主要做两件事:
- 编译代码,使浏览器能识别运行。
开发时我们有样式资源、字体图标、图片资源、html资源等,webpack默认都不能处理这些资源,所以我们要加载配置来编译这些资源。
- 代码质量检查,树立代码规范。
提前检查代码的一些隐患,让代码运行时能更加健壮。
提前检查代码规范和格式,统一团队编码风格,让代码更优雅美观。
处理样式资源
学习使用webpack处理Css、Less、Sass、Styl样式资源
介绍
webpack 本身是不能识别样式资源的,所以我们需要借助Loader来帮助webpack解析样式资源。
需要的Loader都应该去官方文档中查找对应的Loader。
webpack 官方Loader文档
处理CSS资源
- 下载包
npm i css-loader style-loader -D
需要下载两个Loader
-
功能介绍
css-loader
:负责将CSS文件编译成webpack能识别的模块。style-loader
:会动态创建一个style
标签,里面放置webpack中的CSS模块内容。
-
配置
module: {
// loader的配置
rules: [{
test: /\.css$/,
use: [
// 执行的顺序,从右到左(从上到下)
"style-loader", // 将js中css通过创建style标签添加html文件中生效
"css-loader" // 将样式编译成commonjs的模块
]
}]
},
处理less文件
- 下载包
npm i -D less-load
- 功能介绍
less-loader
:负责将less文件编译成CSS文件 - 配置
module: {
// loader的配置
rules: [ {
test: /\.less$/,
// loader:'xxx'只能使用单个loader
// user 使用多个loader
use: [
"style-loader",
"css-loader",
"less-loader" // 将Less 编译成css文件
]
}]
},
处理Sass和Scss资源
- 下载包
npm i sass-loader sass -D
注意:需要下载两个
- 功能介绍
sass-loader
:负责将Sass文件编译成Css文件。sass
:sass-loader
依赖sass
进行编译。
- 配置
module: {
// loader的配置
rules: [{
test: /\.s[ac]ss$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
}]
},
处理styl资源
- 下载包
npm i stylus-loader -D
-
功能介绍
stylus-loader
:负责将Styl文件编译成Css文件。
-
配置
module: {
// loader的配置
rules: [{
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
"stylus-loader"
]
}]
},
处理图片资源
webpack4 时,我们处理图片资源通过file-loader
和url-loader
进行处理。
现在webpack已经将两个Loader功能内置到webpack
- 配置
module: {
// loader的配置
rules: [{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于 10 kb 转base64
// 优点:减少请求数量,缺点:打包后的结果体积增大
maxSize: 20 * 1024,
}
},
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/images/[hash:10][ext][query]"
}
}]
},
自动清空打包内容
output: {
// 文件的输出路径
path: path.resolve(__dirname, "dist"),
filename: "js/main.js",
clean: true
},
处理字体图标资源
- 下载字体文件
- 我用
ttf
文件做测试。 - 放在项目目录中
- 我用
- 在 css 中引入字体
@font-face {
font-family: "HY";
src: url("../fonts/HanYiXingKaiJian-1.ttf");
}
div {
font-family: "HY";
}
- 配置
modules:{
test: /\.ttf|worff?$/,
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/font/[hash:10][ext][query]"
}
}
处理其他资源
如遇到 音视频文件、文本文档等,我们将这些资源打包输出到
dist
目录中。
- 配置
{
test: /\.video|audio|xsl|doc$/,
generator: {
filename: "static/media/[hash:10][ext][query]"
}
}
处理JS资源
webpack对JS处理是有限的,只能编译JS中的模块化语法,不能编译其他语法,导致JS不能在IE等浏览器运行,所以我们希望做一些兼容性处理。
其次,在开发中团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业工具来检测。
- 针对JS兼容性处理,我们手机用
Babel
做代码兼容处理。 - 针对代码格式,我们使用
ESlint
来完成。
先使用 ESlint
做代码检查,然后再使用Babel
做代码兼容性处理。
ESlint
可组装的JavaScript和JSX检查工具。
使用ESlint
关键是使用它的配置文件,里面写的各种rule
规则,将来运行ESlint
时就会以写的规则对代码进行检查。
配置文件
配置文件有很多种写法:
.eslintrc
:新建文件,位于项目根目录.eslintrc
.eslintrc.js
.eslintrc.json
package.json
中eslintConfig
不需要配置文件,在原有的文件基础上写。
ESlint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可。
具体配置
我们以 .eslintrc.js
配置文件为例:
module.exports = {
// 解析选项
parserOptions:{},
// 具体检查规则
rules:{},
// 继承其他规则
extends:[],
}
ESlint 规则
- parserOptions 解析选项
{
parserOptions:{
ecmaVersion: 6 // ES 语法版本
sourceType: "module" // ES 模块化
ecmaFeatures:{
// ES 其他特性
// 如果是 react 项目 需要开启
jsx:true
}
}
}
- rule规则
off
或0
- 关闭规则warn
或1
- 开启规则,使用警告级别的错误:warn
(不会导致程序退出)。error
或2
- 开启规则,使用错误级别的错误:error
(当被触发的时候,程序会退出)。
{
rules:{
semi:"error", // 禁止使用分号
'array-callback-return':'warn', // 强制数组的回调函数中有 return 语句,否则警告。
'default-case':[
'warn', // 要求 switch 语句中有 default分支,否则警告
{
commentPattern:'^no default$' // 允许在最后注释:no default ,就不会有警告。
}
],
eqeqeq:[
'warn', // 强制使用 === 和 !==,否则警告。
'smart' //
]
}
}
- extends 继承
开发中一点点写rules规则太费劲,所以有更好的办法,继承现有的规则。
现有如下较为有名的规则:- Eslint官方规则:
eslint:recommended
- Vue Cli官方规则:
plugin:vue/essential
- React Cli官方规则:
reat-app
- Eslint官方规则:
{
extends:["react-app"],
rules:{
// 我们的规则会覆盖掉react-app的规则
// 所以想要修改规则直接改就行
eqeqeq:["warn","smart"]
}
}
在webpack中使用
- 下载包
npm i eslint-webpack-plugin eslint -D
- 定义Eslint配置文件
.eslintrc.js
import globals from "globals"; import pluginJs from "@eslint/js"; import pluginVue from "eslint-plugin-vue"; /** @type {import('eslint').Linter.Config[]} */ export default [ { files: ["**/*.{js,mjs,cjs,vue}"] }, { languageOptions: { globals: globals.browser } }, pluginJs.configs.recommended, ...pluginVue.configs["flat/essential"], { rules: { "no-var": 2 // 不能使用var定义变量 } }, { ignorePatterns: ["./config/*", "./dist/*", "*.config.js"] } ];
- 下载插件
npm init @eslint/config@latest
- 配置
eslint.config.mjs
import globals from "globals";
import pluginJs from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
/** @type {import('eslint').Linter.Config[]} */
export default [
{ files: ["**/*.{js,mjs,cjs,vue}"] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...pluginVue.configs["flat/essential"],
{
rules: {
"no-var": 2 // 不能使用var定义变量
}
}, {
ignores: ["webpack.config.js", "dist/"]
}
];
- 配置
webpack.config.js
{
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "src")
})
],
}
Babel
JavaScript 编译器。
主要用于将 ES6 语法编写的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或者其他环境中。
配置文件
配置文件有很多种写法:
babel.config.*
:新建文件,位于项目根目录。babel.config.js
babel.config.json
.babelrc.*
:新建文件,位于项目根目录。.babelrc
babelrc.js
bablerc.json
package.json
中babel
:不需要创建文件,在原有文件基础上写。
Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可。
具体配置
我们babel.config.js
配置文件为例:
module.exports = {
// 预设
presets:[]
}
-
presets预设
简单理解:就是一组Babel插件,扩展Babel功能。 -
@babel/preset-env
:智能预设,允许使用最新JavaScript。 -
@babel/preset-react
:用来编译React jsx 语法预设。 -
@babel/preset-typescript
:用来编译TypeScript语法的预设。
webpack中的使用
- 下载包
npm i babel-loader @babel/core @babel/preset-env -D
- 定义Babel配置文件
创建文件babel.config.js
module.exports = {
// 智能预设,编译es6语法
presets: ["@babel/preset-env"]
}
- webpack.config.js 配置文件
{
module:{
test: /\.js$/,
// 排除node_modules中的js文件(这些文件不处理)
exclude: /node_modules/,
loader: "babel-loader"
}
}
处理Html资源
下载包
npm i html-webpack-plugin -D
配置
- webpack.config.js
{
plugins:[
new htmlWebpackPlugin({
template:path.resolve(__dirname,"public/html")
})
]
}
开发服务器&自动化
自动化编译代码
下载包
npm i webpack-dev-server -D
配置
- webpack.config.js
{
// 开发服务器不会输出资源,在内存中编译打包的
devServer: {
// 启动服务器域名
host: "localhost",
port: "3000",
open: true
},
}
- 运行指令
npx webpack serve
总结
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require("path")
module.exports = {
//入口
entry: "./src/main.js",
// 输出
output: {
// 文件的输出路径
path: path.resolve(__dirname, "dist"),
filename: "main.js",
clean: true
},
// 加载器
module: {
// loader的配置
rules: [{
test: /\.css$/,
use: [
// 执行的顺序,从右到左(从上到下)
"style-loader", // 将js中css通过创建style标签添加html文件中生效
"css-loader" // 将样式编译成commonjs的模块
]
}, {
test: /\.less$/,
// loader:'xxx'只能使用单个loader
// user 使用多个loader
use: [
"style-loader",
"css-loader",
"less-loader" // 将Less 编译成css文件
]
}, {
test: /\.s[ac]ss$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
}, {
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
"stylus-loader"
]
}, {
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于 10 kb 转base64
// 优点:减少请求数量,缺点:打包后的结果体积增大
maxSize: 20 * 1024,
}
},
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/images/[hash:10][ext][query]"
}
}, {
test: /\.ttf|worff?$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/font/[hash:10][ext][query]"
}
}, {
test: /\.video|audio|xsl|doc$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/media/[hash:10][ext][query]"
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
},
// 插件
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "src")
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "./index.html")
})
],
devServer: {
// 启动服务器域名
host: "localhost",
port: "3000",
open: true
},
// 模式
mode: "development"
}
生产环境搭建
- 根目录下创建文件夹
config
存放文件webpack.dev.js
、webpack.prod.js
- webpack.dev.js
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require("path")
module.exports = {
//入口
entry: "./src/main.js",
// 输出
output: {
// 文件的输出路径
path: undefined,
filename: "main.js",
clean: true
},
// 加载器
module: {
// loader的配置
rules: [{
test: /\.css$/,
use: [
// 执行的顺序,从右到左(从上到下)
"style-loader", // 将js中css通过创建style标签添加html文件中生效
"css-loader" // 将样式编译成commonjs的模块
]
}, {
test: /\.less$/,
// loader:'xxx'只能使用单个loader
// user 使用多个loader
use: [
"style-loader",
"css-loader",
"less-loader" // 将Less 编译成css文件
]
}, {
test: /\.s[ac]ss$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
}, {
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
"stylus-loader"
]
}, {
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于 10 kb 转base64
// 优点:减少请求数量,缺点:打包后的结果体积增大
maxSize: 20 * 1024,
}
},
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/images/[hash:10][ext][query]"
}
}, {
test: /\.ttf|worff?$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/font/[hash:10][ext][query]"
}
}, {
test: /\.video|audio|xsl|doc$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/media/[hash:10][ext][query]"
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
},
// 插件
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src")
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../index.html")
})
],
devServer: {
// 启动服务器域名
host: "localhost",
port: "3000",
open: true
},
// 模式
mode: "development"
}
- webpack.prod.js
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require("path")
module.exports = {
//入口
entry: "./src/main.js",
// 输出
output: {
// 文件的输出路径
path: path.resolve(__dirname, "dist"),
filename: "main.js",
clean: true
},
// 加载器
module: {
// loader的配置
rules: [{
test: /\.css$/,
use: [
// 执行的顺序,从右到左(从上到下)
"style-loader", // 将js中css通过创建style标签添加html文件中生效
"css-loader" // 将样式编译成commonjs的模块
]
}, {
test: /\.less$/,
// loader:'xxx'只能使用单个loader
// user 使用多个loader
use: [
"style-loader",
"css-loader",
"less-loader" // 将Less 编译成css文件
]
}, {
test: /\.s[ac]ss$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
}, {
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
"stylus-loader"
]
}, {
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于 10 kb 转base64
// 优点:减少请求数量,缺点:打包后的结果体积增大
maxSize: 20 * 1024,
}
},
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/images/[hash:10][ext][query]"
}
}, {
test: /\.ttf|worff?$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/font/[hash:10][ext][query]"
}
}, {
test: /\.video|audio|xsl|doc$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/media/[hash:10][ext][query]"
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
},
// 插件
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src")
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../index.html")
})
],
// devServer: {
// // 启动服务器域名
// host: "localhost",
// port: "3000",
// open: true
// },
// 模式
mode: "production"
}
- 修改
package.json
{
"scripts": {
"dev": "webpack server --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js"
},
}
CSS处理
提取CSS成单独文件
CSS 文件目前是被打包到JS文件中,当JS文件加载时,会创建一个style标签来生成样式。
这样对网站来说,会出现闪屏现象,用户体验不太好。
我们应该将CSS文件提取,通过link
标签引入。
- 下载包
npm i install mini-css-extract-plugin -D
- 配置
webpack.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin({
})],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};
CSS兼容处理
- 下载包
npm i postcss-loader postcss postcss-preset-env -D
- 配置
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path")
function getStyleloader(pre) {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
//入口
entry: "./src/main.js",
// 输出
output: {
// 文件的输出路径
path: path.resolve(__dirname, "dist"),
filename: "main.js",
clean: true
},
// 加载器
module: {
// loader的配置
rules: [{
test: /\.css$/,
use: getStyleloader()
}, {
test: /\.less$/,
// loader:'xxx'只能使用单个loader
// user 使用多个loader
use: getStyleloader("less-loader")
}, {
test: /\.s[ac]ss$/,
use: getStyleloader("sass-loader")
}, {
test: /\.styl$/,
use: getStyleloader("stylus-loader")
}, {
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于 10 kb 转base64
// 优点:减少请求数量,缺点:打包后的结果体积增大
maxSize: 20 * 1024,
}
},
generator: {
// 输出图片名称
// [hash:10] hash 值取前10位
filename: "static/images/[hash:10][ext][query]"
}
}, {
test: /\.ttf|worff?$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/font/[hash:10][ext][query]"
}
}, {
test: /\.video|audio|xsl|doc$/,
generator: {
// [hash:10] hash 值取前10位
filename: "static/media/[hash:10][ext][query]"
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
},
// 插件
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src")
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../index.html")
}),
new MiniCssExtractPlugin({
filename: "static/css/index.css"
})
],
// devServer: {
// // 启动服务器域名
// host: "localhost",
// port: "3000",
// open: true
// },
// 模式
mode: "production"
}
- package.json
{
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
]
}
CSS压缩
- 下载包
npm i css-minimizer-webpack-plugin -D
- 配置
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
plugins: [
new CssMinimizerPlugin()
],
}
html压缩
默认生产模式已经开启了html压缩和js压缩,不需要额外配置。