一、介绍
1.什么是webpack
是前端工程化的具体解决方案
2.主要功能
提供了友好的前端模块化开发支持,以及代码混淆、处理浏览器端js的兼容,性能优化等强大功能
3.优点:
提高了开发效率和可维护性,降低了开发难度
4.用于:
目前Vue和react 等前端项目,基本上都是基于webpack进行工程化开发的
二、使用
1.新建一个文件夹
文件夹只能是英文和数字,不能有“中文” “ . ” “空格”
2.初始化包管理配置文件
在文件的路径上打上cmd进入dos环境。然后输入
npm init -y
这一步是为了初始 化包管理配置文件。
文件夹csdn中生成一个webpack,json的文件
3.安装webpack
npm install webpack webpack-cli -D
-D等价于—save-dev。意为:本地安装
扩展:-g 意为:全局安装
install:可以缩写为 i
4.src配置
新建src 空白文件夹,用于存储源代码。(程序员写的源代码都存储于src中)
创建
index.js
和 indexUntil.js
,index.js
依赖indexUntil.js
index
Until.js 写入
var show = console.log('show'); module.exports = { show }
index.js 写入
require("./indexUntil")
然后在dos中输入
webpack ./src/js/index.js -o ./dist
就会生成dist 文件夹
然后再在 src 文件夹中创建一个html文件夹把这个main.js文件导入就可以了
webpack会以 ./src/js/index.js 为入口文件开始打包,打包后输出到 ./dist 整体打包环境,是开发环境
结论:
-
webpack 本身能处理 js/json 资源,不能处理 css/img 等其他资源,需借助loader
-
生产环境和开发环境将 ES6 模块化编译成浏览器能识别的模块化,但是不能处理 ES6 的基本语法转化为 ES5(需要借助 loader)
-
生产环境比开发环境多一个压缩 js 代码
新建一个info.js使用ES6的语法导出
info.js
//es6语法导出
export default {
name:'zzz',
age:24,
}
main.js导入info.js
//使用es6语法导入
import info from './info.js'
console.log(info.name)
console.log(info.age)
再次使用
webpack ./src/js/index.js -o ./dist
,重新打包
5、Webpack .config.js配置
在根目录创建一个名为
webpack.config.js
的文件,在里面用node.js语言,导出一个webpack配置对象(config:意为配置,module意为模块 export意为出口)。
//path是node里面的一个模块不导入不能用
const path = require('path')
module.exports = {
//mode意为 模式。而webpack模式有两种一种是 development:开发者模式;另一种是production生产模式(上线模式)
mode: 'development',
entry: './src/index.js', //入口文件
output: {
//动态获取打包后的文件路径,path.resolve拼接路径
//__dirname就表示这个文件所处的目录,即根目录
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js', //打包后的文件名
},
}
注:
1.path是node里面的一个模块不导入不能用
2.mode意为 模式。而webpack模式有两种一种是 development:开发者模式;另一种是production上线模式
3.entry:入口文件
4.动态获取打包后的文件路径,path.resolve拼接路径
5.__dirname就表示这个文件所处的目录,即根目录
6.filemane 打包后名字
然后在package.json中的‘scripts’中写上
"dev":"webpack"
这样写是声明一 个脚本 ,其中dev可以随意起名(scripts:意为脚本)
然后就可以通过输入 npm run dev 启动。
补充:
entry:文件入口,即wepack以哪个文件夹为入口,用以分析构建内部依赖图,并进行打包
output:文件出口,即打包好的文件输出在哪,名叫什么
loader:webpack本身无法识别js以外的程序,所以要借助loader来处理
plugins:插件用于执行范围更广的任务,插件的范围包括从打包和压缩,一直到重新定义环境中的变量等。
mode:Webpack使用相应模式的配置。分为development和production两种模式。其中development是开发模式,能让代码本地运行的环境;production是生产模式,能让代码优化运行的环境。
webpack.config.js:webapck的配置文件,当你打包构建前,是先进入webpack.config.js文件中读取文件中的配置,然后基于这些配置来打包项目。
6.css文件处理
1.创建css文件index.css
body {
background-color: red;
}
2.在index.js文件中引入
require("../css/index.css")
3.在dos中下载style-loader和css-loader
npm install --save-dev css-loader style-loader
4.在webpack.config.js中配置
module: {
rules: [{
test: /\.css$/, //正则表达式匹配css文件
//css-loader只负责css文件加载,不负责解析,要解析需要使用style-loader
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
] //使用loader
}]
}
其中 test: /\.css$/,是正则表达式。
test() 方法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。$是结束的意思。
css-loader用于加载css文件,style-loader用于将样式解析到dom文件中。
最后运行npm run dev。css配置结束
7.less文件处理
1.在css文件夹中新增一个less文件
special.less
@fontSize:50px;//定义变量字体大小 @fontColor:orange;//定义变量字体颜色 body{ font-size: @fontSize; color: @fontColor; }
2.index.js中导入less文件模块
//5.依赖less文件 require('./css/special.less') //6.向页面写入一些内容 document.writeln("hello,zzzz!")
3.安装使用less-loader
npm install --save-dev less-loader less
4.在webpack.config.js中配置
module: {
rules: [{
test: /\.less$/, //正则表达式匹配css文件
//css-loader只负责css文件加载,不负责解析,要解析需要使用style-loader
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
,
{
loader: 'less-loader'
}
] //使用loader
}]
}
8. 图片文件的处理
1.安装loader
npm install --save-dev file-loader url-loader
2.在webpack.config.js中配置
module: {
rules: [{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
} //把打包的图片放到images文件夹
}]
}
图片大小小于8kb,就会被base64处理(此时使用url-loader),优点:减少请求数量(减轻服务器压力),缺点:图片体积会更大(文件请求速度更慢)
9. 打包html资源
1.为什么需要打包html资源
直接在src中的html文件中写入标签会报错,所以需要引用插件
2.引用node.js中的插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
//同时要在下面配置
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
其中 const HtmlWebpackPlugin = require('html-webpack-plugin'); 是导入一个html的插件,使HtmlWebpackPlugin成为构造函数。
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})]
通过plugins节点,在其中创建html的实例对象,用以使html插件生效。
以下是完整代码段
const path = require('path')
//导入html插件得到一个构造函数
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
//mode: 'development',
entry: './src/js/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/main.js'
},
plugins: [
//根据构造函数创建html的一个实例对象
new HtmlWebpackPlugin({
//源文件的存放路径
template: './src/index.html',
//生成文件的存放路径和文件名
filename: 'index.html'
})
],
module: {
rules: [{
test: /\.css$/,
use: [{
loader: 'style.loader'
},
{
loader: 'css-loader'
}
]
}, {
test: /\.less$/,
use: [{
loader: 'style.loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
}, {
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
} //把打包的图片放到images文件夹
},
]
},
3.下载html-loader和html-webpack-plugin 插件
npm install --save-dev html-loader html-webpack-plugin
4.在module中配置
{
test: /\.html$/i,
loader: "html-loader",
},
10.打包其他资源
在以上的配置结束后,剩下的格外简单,只要白这些代码导入module(模块)就可以了
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除html|js|css|less|jpg|png|gif文件
exclude: /\.(html|js|css|less|jpg|png|gif)/,
// file-loader:处理其他文件
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'fonts',
},
},
或者
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fontss/[hash][ext][query]'
}
},
11.开发服务器自动化
1. devServer作用
开发服务器 devServer:用来自动化,不用每次修改后都重新输入webpack打包一遍(自动编译,自动打开浏览器,自动刷新浏览器)
特点:只会在内存中编译打包,不会有任何输出(不会像之前那样在外面看到打包输出的build包,而是在内存中,关闭后会自动删除)
2.下载webpack-dev-server
npm install --save-dev webpack-dev-server
3.此代码和module同级
devServer: {
// 项目构建后路径
//contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true,
},
4.启动devServer指令为:
npx webpack-dev-server
5.此时全代码为
//path是node里面的一个模块不导入不能用
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//mode意为 模式。而webpack模式有两种一种是 development:开发者模式;另一种是production生产模式(上线模式)
mode: 'development',
entry: './src/js/index.js', //入口文件
output: {
//动态获取打包后的文件路径,path.resolve拼接路径
//__dirname就表示这个文件所处的目录,即根目录
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js', //打包后的文件名
},
plugins: [
//根据构造函数创建html的一个实例对象
new HtmlWebpackPlugin({
//源文件的存放路径
template: './src/index.html',
//生成文件的存放路径和文件名
filename: 'index.html',
})
],
module: {
rules: [{
test: /\.css$/, //正则表达式匹配css文件
//css-loader只负责css文件加载,不负责解析,要解析需要使用style-loader
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
] //使用loader
},
{
test: /\.less$/, //正则表达式匹配css文件
//css-loader只负责css文件加载,不负责解析,要解析需要使用style-loader
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
}
] //使用loader
}, {
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
} //把打包的图片放到images文件夹
}, {
test: /\.html$/i,
loader: "html-loader",
},
]
},
devServer: {
// 项目构建后路径
//contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true,
},
}
注:此时
plugins: [
//根据构造函数创建html的一个实例对象
new HtmlWebpackPlugin({
//源文件的存放路径
template: './src/index.html',
//生成文件的存放路径和文件名
filename: 'index.html',
})
]
中的 filename: 'index.html', 必须是index.html
12.压缩css并将css从js中提取出来
1.下载插件
npm install --save-dev mini-css-extract-plugin css-minimizer-webpack-plugin
其中插件 css-minimizer-webpack-plugin 优化和压缩 CSS,而 mini-css-extract-plugin 用于把CSS 提取到单独的文件中
2.引用插件并配置
const MiniCssExtractPlugin = require('mini-css-extract-plugin') //提取css成单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //压缩css
plugins: [
new MiniCssExtractPlugin({
filename: 'css/bundle.css'
}),
//提取css 提取时要使用MiniCssExtractPlugin.loader 而且不要对其加引号
new CssMinimizerPlugin()
]
将style-loader改为MiniCssExtractPlugin.loader(注MiniCssExtractPlugin.loader不加引号)
{
test: /\.css$/,
use: [{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
}
]
}, {
test: /\.less$/,
use: [{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
}
13.postcss
1.为什么用postcss
postcss-loader能处理css兼容性
2.下载
npm install --save-dev postcss-loader postcss postcss-preset-env
3.配置
const commonCssLoader = [
// 这个loader取代style-loader。作用:提取js中的css成单独文件然后通过link加载
MiniCssExtractPlugin.loader,
// css-loader:将css文件整合到js文件中
// 经过css-loader处理后,样式文件是在js文件中的
// 问题:1.js文件体积会很大2.需要先加载js再动态创建style标签,样式渲染速度就慢,会出现闪屏现象
// 解决:用MiniCssExtractPlugin.loader替代style-loader
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-preset-env', //这个需要安装npm install postcss-preset-env否则不能生效
{
// 其他选项
},
],
],
},
},
},
]
module: {
rules: [{
test: /\.css$/,
use: [...commonCssLoader],
}, {
test: /\.less$/,
use: [...commonCssLoader,
'less-loader'
]
}
]
},
/*
postcss-loader:css兼容性处理:postcss --> 需要安装:postcss-loader postcss-preset-env
postcss需要通过package.json中browserslist里面的配置加载指定的css兼容性样式
在package.json中定义browserslist:browserslist里面的注释一定要删掉 否则报错
"browserslist": {
// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
"development": [ // 只需要可以运行即可
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境。默认是生产环境
"production": [ // 需要满足绝大多数浏览器的兼容
">0.02%",
"not dead",
"not op_mini all"
]
},
*/
删除注释后的代码
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.02%",
"not dead",
"not op_mini all"
]
}
14.js压缩和html压缩
js压缩
把mode中的 development 改为 production 就自动压缩了
html压缩
在
new HtmlWebpackPlugin({
//源文件的存放路径
template: './src/index.html',
filename: 'index.html'
})
中加入
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
}
15.使用babel-loader来处理js的兼容性问题
用于处理js的高级语言
1.下载
npm install -D babel-loader @babel/core @babel/preset-env
2.代码
{
//npm install -D babel-loader @babel/core @babel/preset-env
test: /\.js$/,
exclude: /node_modules/,// 忽略node_modules
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env']
]
}
}
最后完整的代码
//path是node里面的一个模块不导入不能用
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin') //提取css成单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //新的压缩css
const commonCssLoader = [
// 这个loader取代style-loader。作用:提取js中的css成单独文件然后通过link加载
MiniCssExtractPlugin.loader,
// css-loader:将css文件整合到js文件中
// 经过css-loader处理后,样式文件是在js文件中的
// 问题:1.js文件体积会很大2.需要先加载js再动态创建style标签,样式渲染速度就慢,会出现闪屏现象
// 解决:用MiniCssExtractPlugin.loader替代style-loader
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-preset-env', //这个需要安装npm install postcss-preset-env否则不能生效
{
// 其他选项
},
],
],
},
},
},
]
module.exports = {
//mode意为 模式。而webpack模式有两种一种是 development:开发者模式;另一种是production生产模式(上线模式)
mode: 'development',
entry: './src/js/index.js', //入口文件
output: {
//动态获取打包后的文件路径,path.resolve拼接路径
//__dirname就表示这个文件所处的目录,即根目录
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js', //打包后的文件名
},
plugins: [
//根据构造函数创建html的一个实例对象
new HtmlWebpackPlugin({
//源文件的存放路径
template: './src/index.html',
filename: 'index.html',
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
}
}),
new MiniCssExtractPlugin({
filename: 'css/bundle.css'
}),
//提取css 提取时要使用MiniCssExtractPlugin.loader 而且不要对其加引号
new CssMinimizerPlugin()
],
module: {
rules: [{
test: /\.css$/,
use: [...commonCssLoader],
}, {
test: /\.less$/,
use: [...commonCssLoader,
'less-loader'
]
}, {
test: /\.html$/i,
loader: "html-loader",
}, {
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
} //把打包的图片放到images文件夹
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[hash][ext][query]'
} //把打包的图片放到fonts文件夹
},
{
//npm install -D babel-loader @babel/core @babel/preset-env
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env']
]
}
}
]
},
devServer: {
// 项目构建后路径
//contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true,
hot: true
},
//开发调试阶段精准定位哪个文件错误
devtool: 'eval-source-map'
//上线阶段精准定位哪个文件错误,但不会暴漏源码
//devtool: 'nosources-source-map'
}
三、webpack优化配置
1. HMR(模块热替换)
HMR: hot module replacement 热模块替换 / 模块热替换
作用:一个模块发生变化,只会重新打包构建这一个模块(而不是打包所有模块) ,极大提升构建速度
代码:只需要在 devServer 中设置 hot 为 true,就会自动开启HMR功能(只能在开发模式下使用)
devServer: {
//contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR功能
// 当修改了webpack配置,新配置要想生效,必须重启webpack服务
hot: true
}
每种文件实现热模块替换的情况:
-
样式文件:可以使用HMR功能,因为开发环境下使用的 style-loader 内部默认实现了热模块替换功能
-
js 文件:默认不能使用HMR功能(修改一个 js 模块所有 js 模块都会刷新)
--> 实现 HMR 需要修改 js 代码(添加支持 HMR 功能的代码)
// 绑定 if (module.hot) { // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效 module.hot.accept('./print.js', function() { // 方法会监听 print.js 文件的变化,一旦发生变化,只有这个模块会重新打包构建,其他模块不会。 // 会执行后面的回调函数 print(); }); }
注意:HMR 功能对 js 的处理,只能处理非入口 js 文件的其他文件。
-
html 文件: 默认不能使用 HMR 功能(html 不用做 HMR 功能,因为只有一个 html 文件,不需要再优化)
使用 HMR 会导致问题:html 文件不能热更新了(不会自动打包构建)
解决:修改 entry 入口,将 html 文件引入(这样 html 修改整体刷新)
entry: ['./src/js/index.js', './src/index.html']
2 .source-map
source-map:一种提供源代码到构建后代码的映射的技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
参数:[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
代码:
devtool: 'eval-source-map'
可选方案:[生成source-map的位置|给出的错误代码信息]
- source-map:外部,错误代码准确信息 和 源代码的错误位置
- inline-source-map:内联,只生成一个内联 source-map,错误代码准确信息 和 源代码的错误位置
- hidden-source-map:外部,错误代码错误原因,但是没有错误位置(为了隐藏源代码),不能追踪源代码错误,只能提示到构建后代码的错误位置
- eval-source-map:内联,每一个文件都生成对应的 source-map,都在 eval 中,错误代码准确信息 和 源代码的错误位
- nosources-source-map:外部,错误代码准确信息,但是没有任何源代码信息(为了隐藏源代码)
- cheap-source-map:外部,错误代码准确信息 和 源代码的错误位置,只能把错误精确到整行,忽略列
- cheap-module-source-map:外部,错误代码准确信息 和 源代码的错误位置,module 会加入 loader 的 source-map
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发/生产环境可做的选择:
开发环境:需要考虑速度快,调试更友好
- 速度快( eval > inline > cheap >... )
- eval-cheap-souce-map
- eval-source-map
- 调试更友好
- souce-map
- cheap-module-souce-map
- cheap-souce-map
最终得出最好的两种方案 --> eval-source-map(完整度高,内联速度快) / eval-cheap-module-souce-map(错误提示忽略列但是包含其他信息,内联速度快)
生产环境:需要考虑源代码要不要隐藏,调试要不要更友好
- 内联会让代码体积变大,所以在生产环境不用内联
- 隐藏源代码
- nosources-source-map 全部隐藏
- hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
最终得出最好的两种方案 --> source-map(最完整) / cheap-module-souce-map(错误提示一整行忽略列)
未完待续······