本文编写基于
1.入门(熟悉一下webpack的配置)
1.1创建一个工程化项目
这样会在当前文件下生成一个package.json文件
@1 工程化一个项目
npm init -y
@2 按照官方要求我们下载两个包
npm i webpack webpack-cli -D
- 默认安装在生产环境下
production
- -D安装在开发环境下
development
webpack是按照依赖打包 所有安装在开哪个环境下最终都会打包 这样区分只是为了规范
@3 在根目录下创建一个src 并且创建一个 index.js
@4 修改package.json
@5 执行
npm run build1
到此已经 完成了webpack的简单打包 你会看到根目录下生成了一个dist
文件夹
1.2 介绍核心配置
首先要知道webpack的底层是基于express写的,express是基于nodejs开发的所以我们在配置文件 webpack.config.js 中要遵循CommonJS的规范
@1 创建一个 webpack.config.js
在根目录下创建一个 webpack.config.js 之后我们可以在这个文件中配置webpack (就是在webpack中写规则)
@2 导出配置
// @1 方法一
module.exports = {
}
// @2 方法二
module.exports = function (){
// 这里可以用arguments命令接口传递的参数
console.log(arguments);
return {
}
}
如何用命令接口传参呢?
方法二中的输出
@3 核心概念
模式 mode
通过选择 development
, production
或 none
之中的一个,来设置 mode
参数
module.exports = {
mode: 'production',
};
入口 entry
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。
webpack 会递归的构建一个 *依赖关系图*
下文会分析打包后的文件
一个入口
module.exports = {
//无论配置文件在哪里./都是根目录
entry: './src/index.js',
};
多个入口
等待写
输出 output
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js
,其他生成文件默认放置在 ./dist
文件夹中。
- path 打包后的文件放在哪里
- filename 打包后的文件名称
const path = require('path');
module.exports = {
output: {
// 必须是个绝对地址
path: path.resolve(__dirname, 'dist'),
filename: 'mydist,
},
};
loader
什么是loader
?
让我们一起看看官方文旦怎么说
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)
下面1.3.2会具体说明
让我们通过代码来进一步了解一下loader
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
以上配置中,对一个单独的 module 对象定义了 rules
属性,里面包含两个必须属性:test
和 use
。这告诉 webpack 编译器(compiler) 如下信息:
“嘿,webpack 编译器,当你碰到「在
require()
/import
语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先 use(使用)raw-loader
转换一下。”
下面我们会细说一下常用的loader
插件 plugin
让我们看看官方介绍
想要使用一个插件,你只需要
require()
它,然后把它添加到plugins
数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用new
操作符来创建一个插件实例。
@1 引入
@2 在plugins数组中 new 出来
在这一步我们简单了解一下如何使用plugin 就好
下面我们会细说一下常用的 plugin
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' })
],
};
1.3一些基本需求
1.3.1 引入html 使其与 打包好的js自动关联
@1 npm i -D html-webpack-plugin
这是一个plugin 所以遵循上面所说的plugin的使用规则
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin()
]
}
new HtmlWebpackPlugin()中传入一个对象中有些常用参数
-
template 指定html模板地址 string
-
templateContent 指定模板
templateContent = `<html> ..... </html>`
-
filename 打包后的文件名字
//[hash]会随机生成hash值 对清除缓存很有效 filename:'webpack[hash].html'
-
title 指定html1的title 前提是你遵循了ejs的语法
<title><%= htmlWebpackPlugin.options.title %></title>
我们可以这样玩
@1 在根目录下新建一个public文件夹
@2 在public文件夹下创建一个index.html 为html模板
@3 配置
plugins:[ new HtmlWebpackPlugin({ template:'./public/index.html' }) ]
@4 打包
之后就可以在dist文件夹下看到生成了一个index.html并且自动帮我们关联上打包的js
1.3.2 每次打包清除之前打包的文件
@1 引入
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
@2 使用一下plugin
plugins:[
CleanWebpackPlugin();
]
这样以后你会发现每次npm run build
都是一个新的dist
1.3.3 引入css
因为webpack只认识js和json文件所以你需要引入loader告诉 webpack 加载 CSS 文件
@1 安装相关loader
npm install css-loader style-loader
@2 引入css到js中
import './test.css'
@3 配置loader
module: {
rules: [
{
test:/\.txt$/,
use:'raw-loader'
},
{
test:/\.css$/,
// 从右向左解析原则
use:['style-loader','css-loader']
},
]
},
先执行 css-loader
- css-loader 的作用是处理css中的外部资源
- 通俗的说就是把import/require 引入的css变成webpack认识的资源
再执行 style-loader
+ 把样式插入到 DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的 innerHTML里
之后打包的index.html中就会有样式
1.3.4 提高引入css的兼容性
为啥要引入 postcss-loader 呢
图
@1 安装
npm install --save-dev postcss-loader postcss
@2 使用方法
-
在loader中引入
-
在根目录下写一个postcss.config.js配置文件
module.exports = { plugins: [ [ "postcss-preset-env", { // Options }, ], ], };
-
配置 .browserslistrc
那什么是browserslistrc呢?
可以参考这个
cover 99.9%
- 兼容市面上百分之99.9的浏览器
这东西主要是配置浏览器兼容性
//.browserslistrc
last 1 version
> 1%
maintained node versions
not dead
1.3.5 拆分css
由直接插入style标签转为link引入
@1 安装
npm install --save-dev mini-css-extract-plugin
@2 使用
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
- filename 打包后的css放在dist的哪里
1.3.5 引入图片
在 webpack 5 之前,通常使用:
raw-loader
将文件导入为字符串url-loader
将文件作为 data URI 内联到 bundle 中file-loader
将文件发送到输出目录
我们先使用一下url-loader
file-loader
@1 安装
npm install url-loader file-loader --save-dev
@2 引入图片资源
import img from './image.png';
@3 配置
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 1024 * 50,
name:'imgs/[name].[ext]'
},
},
],
},
- limit 限制大小 1024 * 50 就是 50kb
- name 文件放到哪里 【name】表示原来的名字 【ext】表示原来的文件后缀
官网说如果超过了limit限制的大小就会使用file-loader
就是说没超过是一个 base64的图片 不会把图片打包过去
超过了是一个http路径地址 会把图片打包过去
使用base64可以减少http请求优化网页
效果
图片原本大小51.4KB 我设置的limit是50kb
webpack5
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
asset/resource
发送一个单独的文件并导出 URL。之前通过使用file-loader
实现。asset/inline
导出一个资源的 data URI。之前通过使用url-loader
实现。asset/source
导出资源的源代码。之前通过使用raw-loader
实现。asset
在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用url-loader
,并且配置资源体积限制实现。
举一个例子打包成base64
{
test: /\.(png|jpg|gif)$/i,
type: 'asset/inline'
}
那么asset/resource打包后的图怎么指定路径和文字呢
看一眼官方文档
默认情况下,
asset/resource
模块以[hash][ext][query]
文件名发送到输出目录。可以通过在 webpack 配置中设置
output.assetModuleFilename
来修改此模板字符串:
所以我们需要在output中设置
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'mywebpack.js',
assetModuleFilename: 'images/[name][ext]'
},
1.4 拆分配置文件/拆分webpack.config.js
看一眼官方怎么说
development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异。在开发环境中,我们需要:强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。而生产环境目标则转移至其他方面,关注点在于压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
虽然,以上我们将 生产环境 和 开发环境 做了细微区分,但是,请注意,我们还是会遵循不重复原则(Don't repeat yourself - DRY),保留一个 "common(通用)" 配置。为了将这些配置合并在一起,我们将使用一个名为
webpack-merge
的工具。此工具会引用 "common" 配置,因此我们不必再在环境特定(environment-specific)的配置中编写重复代码。
@1 安装
npm install --save-dev webpack-merge
@2 新建一个config目录
把原先的webpack.config.js拆分
+ 公共配置 webpack.common.js
+ 开发环境配置 webpack.dev.js
+ 生产环境配置 webpack.production
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
@3 写配置
公共配置 webpack.common.js
const path = require("path");
module.exports = {
entry:'./src/index.js',
output:{
path: path.resolve(__dirname),
filename: 'mywebpack.js',
}
}
开发环境配置 webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development'
});
生产环境配置 webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production'
});
2.开发服务器(devServer
)
首先我们要知道 webpack-dev-server 的底层是nodejs 的 http模块
运行它会把打包后的index.html运行
@1 安装
npm i webpack-dev-server
@2 使用webpack-dev-server
配置 @2.1
var path = require('path');
module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
},
};
@2.2 在webpack 后面加上 serve
当服务(server
)启动后,在解析模块列表之前输出一条消息:
接下来就是一些和webpack server相关的属性
contentBase
告诉服务器内容的来源。仅在需要提供静态文件时才进行配置
const path = require('path');
module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'public'),
},
};
before
提供了一个在
devServer
内部的 所有中间件执行之前的自定义执行函数。
看一下官方给的例子
module.exports = {
//...
devServer: {
before: function (app, server, compiler) {
app.get('/some/path', function (req, res) {
res.json({ custom: 'response' });
});
},
},
};
会node express框架的小伙伴有没有觉得很像express 的 接口语法
我们用get请求一下
是可以跑通的
我们可以利用这一特点模拟请求做一些假数据
在模板 index.html中
fetch('/api/list').then((res) => {
return res.json()
}).then((res) => {
console.log(res);
})
webpack.config.js
before: function (app, server, compiler) {
app.get('/api/list', function (req, res) {
res.json({ custom: '你好' });
});
},
open
告诉 dev-server 在服务器启动后打开浏览器。 将其设置为
true
以打开默认浏览器
module.exports = {
//...
devServer: {
open: true,
},
};
proxy
配置代理的 Vue.config.js 和这个差不多它的底层可能是和webpack配置合并
简单写法
module.exports = {
//...
devServer: {
proxy: {
'/api': 'http://localhost:3000',
},
},
};
只要是/api开头的请求都会转发给 http://localhost:3000
拓展写法
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
};
只要是/api开头的请求都会转发给 http://localhost:3000 并且 ‘/api’ 会重写为 空字符串
比如 实际请求的是 /list 接口
axios('/api/list').then(res=>{})
changeOrigin: true
默认情况下,代理时会保留主机头的来源,可以将
changeOrigin
设置为true
以覆盖此行为
这玩意有时候可以有时候可以骗过后端的拦截
比如 localhost:3000 发给 localhost:9000 请求的接口是/list
changeOrigin: true -> 后端获取的源(host / origin) localhost:9000
changeOrigin: false -> 后端获取的源(host / origin) localhost:3000
progress
将运行进度输出到控制台
使用方法
webpack serve --progress
hotOnly
启用热模块替换(请参见
devServer.hot
),而无需页面刷新作为构建失败时的回退. 热更新
webpack.config.js
module.exports = {
//...
devServer: {
hotOnly: true,
},
};
通过命令行使用
webpack serve --hot-only