Webpack的使用(搭建Vue+React环境)
认识Webpack
Webpack
对于目前的前端开发来说具有代表性的模块化打包工具
像常用的三大框架的脚手架,Vue-cli
,create-react-app
,Angular-cli
都是基于Webpack
来进行打包的,常见的场景有,支持开发者使用ES6+语法
,Typescript
,less样式预处理
,实时监听代码变更反馈到应用中
,对最终的开发产出进行压缩打包
等等优化处理
以一个Vue
项目来说,需要通过Webpack
处理的地方就有
- 将单文件组件(
Single File components
)编译 - 如果使用了则需要将
Typescript
转移成Javscript
语法 - 如开发过程用了
ES6+
的语法为了兼容性,需要转化成ES5
或者ES3
等语法代码 - 将
less
,scss
等预处理语法转化成css
- 将转化后的
css
进行模块化提取加载 - 对项目中使用到的资源文件进行处理加载(图片,文字等)
- 打包
HTML
相关资源文件
平时开发不需要自己从零开始搭建,主流的脚手架已经很方便快捷了,但是学习下webpack
的使用还是有助于理解提升的
开始上手
没有安装Node
的先安装
首先需要安装webpack
和webpack-cli
,他们俩的关系属于互相依赖,如果只安装webpack
则无法使用
- 建一个空项目
yarn init -y
创建package.json
yarn add webpack webpack-cli -D
- 执行
webpack
时,默认会在当前目录下的src
找index.js
,这个入口配置可以改,但先按要求建 - 执行
webpack
有几种方式
-
./node_modules/.bin/webpack
找到目标程序执行- 执行
npx webpack
,这里简单说一下npx
是npm5.2.0
新增的一个工具,这行代码执行后,会去当前目录下的node_modules/.bin/webpack
找到他并执行,如果没有则会去全局模块下寻找,还没有就会从源下载并创建一个临时目录,当执行完后就会自行删除 - 在
package.json
编写scripts
,通过yarn
或npm
执行
{
"name": "wp",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"scripts": {
"dev": "webpack"
}
}
执行后应该能看到打包成功的信息,其中红框的警告会告诉你,没有指定任何mode
,会使用值为production
,两种模式的打包会有不同优化和混淆,可供使用的有development
,production
,none
,一般开发用development
,打包时指定production
构建成功后且可以看到当前目录下多了dist/main.js
,这个就是打包后的产出文件,产出目录和入口一样都是可以通过配置去改变
到目前为止已经成功执行了一个"打包行为"
添加配置文件
新建一个webpack.config.js
文件,这个名字webpack
认识,如果用其他命名,则可以通过webpack --config xxx.config.js
用cli
的参数进行指定,下面修改下产出目录文件的配置
const path = require('path');
module.exports = {
mode: "production", // 指定mode为production
entry: "./src/index.js", // 指定打包文件检索的入口,这个就是默认值,可以修改
output: {
// 指定打包产出的目录文件,这里还是指定为当前目录的dist文件夹
// 但是文件名指定成bundle.js
"filename": "bundle.js",
path: path.resolve(__dirname, "./dist")
},
}
修改下script
,这里只是为了演示使用,使用这个名字可以不用加
"scripts": {
"dev": "webpack --config webpack.config.js"
}
再次执行后yarn dev
后就会在看到产出更改为dist/bundle.js
文件了
这是webpack
官网首页图,给定一个入口文件,延展出一张依赖图,并逐个进行打包(需要下文说的loader
)最终产出
了解插件
截止到目前,虽然能打包了,但是没法看到效果,一个web
应用最起码需要一个html
页面,这里可以利用一个插件html-webpack-plugin
进行自动生成并载入bundle
所谓插件就是可以在打包过程再进一步做更多的事情,如优化,注入等操作
- 安装依赖
yarn html-webpack-plugin
- 在项目根目录下新建一个
index.html
模板,内容如下,模板采用ejs
语法,感兴趣的可以了解下,配置了插件后,会将title
的模板变量替换成配置中的值
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
插件配置项与entry
等同级,省略部分代码,配置项是个插件数组
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/main.js",
// ...
plugins: [
new HtmlWebpackPlugin({
title: "webpack好难",
template: "index.html"
})
]
}
此时进行构建还会报错,会提示BASE_URL is not defined
,原因是模板无法找到这个变量,可以再利用一个webpack
的内置插件DefinePlugin
去定义BASE_URL
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
module.exports = {
entry: "./src/main.js",
// ...
plugins: [
new DefinePlugin({
BASE_URL: '"./"'
}),
new HtmlWebpackPlugin({
title: "webpack好难",
template: "index.html"
})
]
}
再次执行webpack
命令,应该能看到产出目录多了一个
index.html
,查看其内容,可以看到有个script
标签把打包后的入口文件自动引入了,link
的值也符合预期
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" href="./favicon.ico" />
<title>webpack好难</title>
<script defer="defer" src="bundle.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
此时再介绍另一个插件,每次构建时自动清理dist
目录,yarn clean-webpack-plugin -D
,安装后使用方式只需要只需要往插件数组添加一个对象实例
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
module.exports = {
// ...
plugins: [
new DefinePlugin({
BASE_URL: '"./"'
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "webpack好难",
template: "index.html"
})
]
}
后续每次构建都会自动清理产出目录
了解Loader
webpack
默认只认识javascript
和json
文件,如css
,png
,typescript
,jsx
,vue
等等它都不认识,这时候需要一个Loader
,去将这些文件转换成模块,并添加到webpack
的依赖关系中,接下来解决样式文件和资源文件导入的问题
在src
目录下新建一个main.css
.red-text{
color:red;
}
接着在index.js
头部中import "./main.css"
import "./main.css";
function addChild() {
const ele = document.createElement("div");
ele.textContent = "函数添加的Div";
ele.classList.add("red-text");
document.body.appendChild(ele);
}
addChild();
执行构建后,会看到错误输出告诉你,需要一个合适的loader
去处理css
文件
处理css
常用的就是css-loader
,添加依赖yarn add css-loader -D
,接着在配置文件中添加module.rules
,这是一个数组,数组每一项可以指定某类文件使用某种loader
进行转换,并可以给loader
传入特定的参数配置
module: {
rules: [
{
test: /.css$/i,
use: "css-loader",
// use: { loader: "css-loader" },
// use: ["css-loader"],
// use: [{ loader: "css-loader" }],
}
]
},
test
的值一般为正则表达式,这里的意思是匹配所有.css
后缀的文件,use
则指定对应的loader
为css-loader
,这里的写法是一种简写,简写下还列出了其他几种写法,loader
可以配置多个,会从下往上
执行,按需编写,再次执行构建就能看到css
文件也成功被webpack
转换加载打包成功
不过此时查看打包后的页面,会发现红色文字样式没有生效,原因在于webpack
只是解析的样式文件,但没有将内容插入到页面当中,此时还需要一个loader
来处理,yarn add style-loader -D
,安装style-loader
后,进行相关配置,由于loader的执行是从下往上,所以需要先经过css-loader
解析,然后再通过style-loader
进行注入,顺序不能错
module: {
rules: [
{
test: /.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
],
}
]
},
此时再次执行构建并查看页面,样式已经生效
在开发中,可能还会使用到less
,scss
等预处理器,使用方式也一样,以less
举例,yarn add less less-loader -D
,安装依赖后进行对应的loader
配置(不能只装loader
,还得装less
),注意顺序一定是先执行的loader
转化结构可以被下一个loader
解析
还有一个postcss-loader可以了解一下
这个loader
可以自动的添加样式浏览器前缀,同时再配合一个loader
的插件postcss-preset-env
,可以将一些现代的css
转成大多浏览器认识的css
,并自动添加前缀
yarn add postcss-loader postcss-preset-env -D
,接着添加配置
{
test: /.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"]
}
}
}
],
},
资源loader
除了样式文件外,常用的还有img
,png
等资源文件,首先在网上随便找一张图片,丢到src/images
目录下,接着修改index.js
增加一个图片引入,实例我找了一张vue
的图片
import "./main.css";
import vueImage from "./images/vue.jpg";
function addChilds() {
const ele = document.createElement("div");
ele.textContent = "函数添加的Div";
ele.classList.add("red-text");
document.body.appendChild(ele);
}
addChilds();
function addImageEle() {
const imgEle = new Image();
imgEle.src = vueImage;
document.body.appendChild(imgEle);
}
addImageEle();
此时直接构建会报上面未添加css-loader
时相同的错误,这里可以使用file-loader
进行加载,并会将文件输出到打包目录下,yarn add file-loader -D
,接着配置资源文件的rule
{
test: /.(png|jpe?g|gif)$/i,
user: {
loader: "file-loader"
}
}
此时执行构建,没有报错且图片也成功输出到页面中
查看dist
目录,可以看到有个jpg
文件,这个命名是可以通过配置生成的
下面配置一下资源文件的命名规则,通过use.options
添加,name
配置可以使用一些placeholders
,具体作用可以查文档 www.webpackjs.com/loaders/fil…
{
test: /.(png|jpe?g|gif|svg)$/i,
use: {
loader: "file-loader",
options: {
name: "[name].[hash:8].[ext]",
outputPath: "img"
}
}
}
构建后可以看到,图片被放在了img
目录下,并且文件名也按照原文件名+hash值取8位+文件后缀
的形式
再介绍另一个 url-loader
和file-loader
有所不同,这个loader
有将资源转换成内联base64
的作用
yarn add url-loader -D
,看效果只需要把file-loader
改成url-loader
,配置可复用,再次构建后,dist
目录下已经木有
下面手动的设置这个配置,配置key
叫做options.limit
,单位是byte
,小于这个大小的文件会被解析成base64
,反之则与file-loader
一样处理
{
test: /.(png|jpe?g|gif|svg)$/i,
use: {
loader: "url-loader",
options: {
name: "[name].[hash:8].[ext]",
outputPath: "img",
limit: 3 * 1024 // 3kb以下就会被处理成base64
}
}
}
如果大资源也弄成了base64
会影响页面请求,需要看时机情况来配置
在css
中,也可能会使用background-image
属性来引入资源文件,在main.css
中添加如下属性,并且作用到div上
.bg{
background-image: url("./images/vue.jpg")
}
构建后查看页面会发现,虽然没有报错,但是图片压根就没显示
此时需要添加两个配置,一个是options
下的esModule:false
,将引入方式改为非(import xx from "yyy")
,第二个是与use
同级的type
,值为javscript/auto
,可以避免重复处理资源
{
test: /.(png|jpe?g|gif|svg)$/i,
use: {
// loader: "file-loader",
loader: "url-loader",
options: {
name: "[name].[hash:8].[ext]",
outputPath: "img",
limit: 3 * 1024,
esModule: false
}
},
type: "javascript/auto"
}
更改后构建就能看到css
背景图生效
webpack5的asset module type
从webpack5
开始,官方文档更推荐的一种使用是asset module
,用于替代这些loader
Asset Modules type replaces all of these loaders by adding 4 new module types:
- asset/resource emits a separate file and exports the URL. Previously achievable by using .file-loader
- asset/inline exports a data URI of the asset. Previously achievable by using .url-loader
- asset/source exports the source code of the asset. Previously achievable by using .raw-loader
- asset automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using with asset size limit.url-loader
asset/resource
可以看成file-loader
的实现asset/inline
可以看成url-loader
的实现asset/source
可以看成raw-loader
的实现,这个loader
的作用是将资源文件导入为字符串(源码)asset
则是在resource
和inline
之间自动选择
现在已经不需要再使用file-loader
和url-loader
了,改写原本的loader
如下
{
test: /.(png|jpe?g|gif|svg)$/i,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:8].[ext]"
}
}
构建后效果完全相同,其中filename
还可以不在这里配置,在output
中配置assetModuleFilename
作用等价,他们可以共存,generator
配置优先
output: {
"filename": "bundle.js",
path: path.resolve(__dirname, "./dist"),
assetModuleFilename: "img/[name].[hash:8].[ext]"
},
实现url-loader
按指定大小自动选择模式
首先将type
改为asset
,再添加一个parse.dataUrlCondition
配置内联条件,这里的定义为小于3kb
的资源才会被处理成base64
{
test: /.(png|jpe?g|gif|svg)$/i,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 3 * 1024
}
}
}
CopyWebpackPlugin
在使用vue/cli
的项目中,放到public
的文件会默认的复制到打包目录当中,实际上可以通过CopyWebpackPlugin
来实现
yarn add copy-webpack-plugin -D
const CopyWebpackPlugin = require("copy-webpack-plugin");
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: "public",
globOptions: {
ignore: ["**/index.html"]
}
}
]
})
]
这里通过一个配置防止public
中也有index.html
,忽略复制这个文件
了解Babel
babel
对于目前的前端开发来说,已经是核心之一,他可以让高阶语法转换成低版本浏览器可兼容代码,以及解析jsx``tsx
等特殊扩展语法。实际上babel
就是一个编译器,将a语法
的代码转换成b语法
的代码,以一个app.jsx
文件为例,先解析
->词法语法转换(AST树)
->生成目标代码
babel实际上可单独使用,无非搭配webpack等构建工具
yarn add @babel/core bebel-loader @babel/preset-env -D
@babel/core
是babel-loader
的依赖,类似于less-loader
依赖less
,@babel/preset-env
是一堆es6+语法插件
的集成包,只有提供插件才能让babel
认识es6+
语法
首先,添加loader
,其次配置插件有两种方式
第一种,直接在loader
的options
里配置预设插件
{
test: /.js?$/i,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
},
另一种是新建一个babel.config.js
module.exports = {
presets: ["@babel/preset-env"]
}
两种方式选择一种即可
尝试引入Vue
并构建
首先安装vue
,yarn add vue
在使用vue
之前,简单了解下vue
的不同版本区别,可以定位到当前目录下node_modules/vue/dist
下,可以看到不同的vue版本
vue(.runtime).global(.prod).js
的版本,是通过在全局对象下暴露一个Vue
对象,实际上可以通过<script src="xxx.js"></script>
的方式进行直接引入使用vue(.runtime).esm-browser(.prod).js
的版本,提供了通过ES
模块的导入方式使用,<script type="module"></script>
vue(.runtime).esm-bundler.js
的版本,提供给webpack
之类的构建工具使用vue.cjs(.prod).js
的版本,提供给服务端渲染,在node
中使用require
以上所有带runtime
的版本都是指不包含编译器的版本(仅运行时
),而不带runtime
的都是完整版(运行时+编译器
)
在打包的入口文件js
中编写包含如下代码,前提是html
模板里必须有一个id
为app
的元素
import { createApp } from "vue";
createApp({
template: "<div>{{ msg }}</div>",
data() {
return {
msg: "test Msg"
}
}
}).mount("#app");
此时执行构建,虽然构建过程没有报错,但是打开页面的控制台能看到如下信息
意思是告诉你,提供的vue
组件包含了template
模板,在import vue from "vue"
这个方式默认引入的实际上是一个只提供运行时
的版本,没有包含内置的模板编译功能
,此时有几种方案
- 第一种是按要求更改为包含模板编译的完整版本(体积会更大)
import { createApp } from "vue/dist/vue.esm-bundler";
- 第二种是使用
render
函数进行渲染(编写麻烦)
import { h } from "vue";
// h函数从vue包中导入
createApp({
// template: "<div>123{{msg}}</div>",
render() {
return h("div", {}, this.msg)
},
data() {
return {
msg: "test msg"
}
}
}).mount("#app");
- 使用
SFC(Single File Component)
,也就是后缀名为vue
的文件,并通过如webpack
的构建工具进行模板编译,满足运行时版本即可执行的条件(主要使用这种方式)
新建一个Main.vue
文件
<template>
<div>vue组件</div>
</template>
<script>
export default {
setup() {
return {}
}
}
</script>
<style scoped>
</style>
接着引入该组件并挂载
import { createApp } from "vue";
import VueApp from "./vue-components/Main.vue";
createApp(VueApp).mount(document.querySelector("#vue-app"));
既然是不认识的文件,那就必需要给webpack
配置对应的loader
,yarn add vue-loader
{
test: /.vue$/i,
loader: "vue-loader"
}
此时执行构建,会看到以下报错
主要看第二行报错信息,告诉你需要在webpack
的配置文件中配置对应的VueLoaderPlugin
,而这个插件通过vue-loader
包引入即可
const { VueLoaderPlugin } = require("vue-loader/dist/index")
//...省略
plugins: [
new VueLoaderPlugin()
]
构建后打开页面,即可看到vue单文件组件成功编译并挂载到页面
但观察控制台,vue3
版本会有一个警告
意思是vue3
版本暴露了两个特性标记给开发者进行覆盖,不配置的话有默认值会照常工作,但是建议我们手动配置,点击地址链接能跳转到解决警告的方式github.com/vuejs/core/…
其中__VUE_OPTIONS_API__
指是否使用Vue
的构造选项
__VUE_PROD_DEVTOOLS__
指在发布模式下,是否支持devtools
开发者工具
webpack
的解决方式只需要在DefinePlugin
中定义这两个配置即可,这个插件上面配置BASE_URL
时已经使用过了,追加键值对即可
plugins: [
new DefinePlugin({
BASE_URL: '"./"',
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
}),
]
再次构建警告便消失
到这里,Vue
框架的引入搭建便已经完成
接着引入React
框架
yarn add react react-dom
,react
需要引入两个库
使用react
一般有两种方式
- 一种是使用类似
vue
中的render
函数编写(自行在index.html
模板添加对应的容器div
)
import React from "react";
import ReactDom from "react-dom";
ReactDom.render(React.createElement("div", {}, ["react组件"]),
document.querySelector("#react-app"));
构建编译后查看页面,react
的引入也成功并挂载到页面上,由于我没有删除vue
相关代码,所以此时这个项目即能编写react
,又能编写vue
不过观察控制台会有一个react18
版本的警告,意思是这个版本虽然能按照旧版17
的样子跑,但不再支持ReactDom.render
的方法,要改用createRoot
,只需要做如下改动警告便会消失
import { createRoot } from "react-dom/client";
import React from "react";
createRoot(document.querySelector("#react-app"))
.render(React.createElement("div", {}, ["react组件"]));
- 一种是通过
js/jsx
扩展文件编写,在js
中编写类html
的代码,但需要特殊的语法解析转义成第一种代码,浏览器才能运行,babel
插件便能完成这项工作(这篇文章不是主讲React
,对jsx
感兴趣的自行了解)
const App = () => {
return (<div>react App 组件</div>)
}
createRoot(document.querySelector("#react-app"))
.render(<App />);
此时构建的话会报错,因为webpack
不认识这种jsx
语法,yarn add @babel/preset-react -D
,添加babel
的预设插件解析语法转译(记得在webpack
配置中配置js
,jsx
的babel-loader
,上文已配置过,此处仅添加插件)
module.exports = {
presets: ["@babel/preset-react", "@babel/preset-env"]
}
构建后查看页面,采用jsx的写法也生效了
devServer
在上面演示中,每一次处理都是手动的去构建代码,理想的开发环境自然是自动检测代码更改并且编译及刷新页面展示
webpack默认提供了自动编译功能
通过webpack --watch
或者webpack
配置文件添加watch:true
启动,但是这种方式不会刷新页面,仅仅编译代码
这时候就需要一个webpack-dev-server
工具
yarn add webpack-dev-server -D
可以通过 webpack serve
,这个cli
的入参有依赖,如果没有安装webpack-dev-server
则会报错
或者直接手动执行webpack-dev-server
启动服务,执行后会启动一个本地服务,并且编译的产出会保存到电脑内存中,不会有对应的产出
在package.json
中添加一个script
:"serve": "webpack serve"
,执行yarn serve
成功的话便能看到以上输出,访问对应的地址可以访问项目
并且对组件内容进行修改后,页面会自动刷新
模块热替换
也称为HRM(Hot Module Replacement)
在程序运行时,动态的增删改局部模块,不需要刷新整个页面,好处在于如果全局刷新,状态无法保存(操作了一半,改下代码就全部重置了),而HRM
则指更新需要更新的模块
可以在webpack.config
中通过devServer.hot
属性去配置布尔值,不过这个属性默认是开启的,但是需要做额外的处理,否则更改代码后仍然全局刷新
首先讲上述的React
组件抽离出去,并在
index.js
中引入组件,并告知webpack
服务对哪些模块进行HMR
,在启动了HRM
的前提下,module.hot
是一个对象,反之则是undefined
,index.js
改写以下代码
import ReactApp from "./react-components/App"
// ...省略其他代码
if (module.hot) {
module.hot.accept("./react-components/App.js", () => {
console.log("react组件局部更新");
})
}
createRoot(document.querySelector("#react-app"))
.render(<ReactApp />);
再次启动服务,并且对react
组件进行修改,可以看到页面不再是全局刷新,而是仅仅更新了React
组件部分,观察控制台,可以看到每更改保存一次文件,传入的回调函数便会执行一次
简单了解下原理
在启动webpack-dev-server
时,实际上启动了两个服务,一个用于获取静态资源服务,一个Socket
长连接服务
- 像页面请求,
css
请求,js
请求属于静态资源服务在处理 - 而
HMR
则是基于Socket
长链接实现,只要监听到文件变更,就会生成两个文件,一个js
和一个json
,通过webSocket
通讯主动告知发送给浏览器,浏览器拿到后经过处理对更新的模块进行局部更新
启动服务修改文件后,通过开发者工具可以看到对应的websocket
链接信息
服务端主动发送的两个更新文件,这里实时更新了两次,所以会有两份js
和json
文件
devServer的可配置项
port
:配置端口,默认是8080
open
:配置服务启动后,是否自动打开浏览器访问,默认是false
proxy
:主要用于解决跨域问题(浏览器和服务器协议,域名,端口任一不一致的安全策略),可以配置代理中间件的规则,值得一提的是,webpack-dev-server
使用的资源服务器是基于express
框架的,而其中的代理配置则是采用了http-proxy-middleware,简单看看使用
devServer: {
open: true,
port: 8888,
proxy: {
"/api": {
target: "http://192.168.8.58:8080",
changeOrigin: true,
pathRewrite: {
"^/api": ""
},
}
}
},
这段proxy
配置的意思是将所有请求资源地址为/api
开头的,都使用代理规则,原本代码里axios.get("/api/hi")
有这么一段请求代码,当前的环境下,他最终会请求http://localhost:8888/api/hi
,而我真实提供api
的接口地址为http://localhost:8080/hi
- 不配置
pathRewrite
的情况下必然会返回404
,那么就需要通过pathRewrite
正则匹配将以/api
的字符替换为空字符串
,那么最终实际代理服务器的请求地址是http://192.168.8.58:8080/hi
changeOrigin
:默认是false
,设置为true
会更改掉请求头中的Host
字段,需要注意的是如果在浏览器的Network
观察是不会有变化的,可以在服务端将请求头打印查看
changeOrigin
为false
的情况下,服务端拿到的请求头数据为当前站点地址
将changeOrigin
设置未true
后,服务端拿到的请求头数据为Proxy
中设置的target
值
secure
:默认为true
,不支持代理转发到https
服务器上,如果要支持可以设置为false
compress
:是否开启gzip
压缩,默认是true
,改为false
则不压缩,目前为false
的情况下,bundle.js
大小为2mb
删掉compress
或者设为true
,当前大小只有457kb
,服务端应该尽可能的压缩来提高传输效率
historyApiFallback
:默认为false
,设置为true
后,页面访问出现404
时会自动将/index.html
的内容返回
Resolve 解析
webpack
默认支持3种形式的解析
- 绝对路径
- 相对路径,当前文件的路径会当做工作目录上下文,如使用
import
导入了一个"../test/a.js"
,那么最终会解析出当前目录的上层目录的test
文件夹的a.js
的绝对路径 - 模块路径,指定解析模块时应该搜索的目录,如
import Vue from "vue"
,由于resolve.modules
默认值是['node_modules']
,所以会去依赖目录中找到对应的文件 - 解析到是文件,有扩展名则直接打包,没有则使用webpack的
resolve.extensions
默认值是[".wasm",".mjs",".js",".json"]
尝试进行解析 - 如果是文件夹,则先根据webpack配置
resolve.mainFiles
的默认值['index']
进行查找对应文件,接着按第四点规则
解析
编写时省略文件后缀名
webpack
默认可省略的配置是 extensions: [".wasm", ".mjs", ".js", ".json", ".vue"],
,这里添加.vue
,后续引入vue
单文件组件便不再需要写xxx.vue
,直接写xxx
即可
extensions: [".wasm", ".mjs", ".js", ".json", ".vue"]
// 也可以通过"..."获取默认配置项
extensions: ["...", ".vue"],
alias
选项设置别名
配置后项目中可以使用对应key
代替配置的路径,可以减少很多层级目录的写法,如有一个较深层的文件想要引用src/utils
下的某个文件,原本要写../../../utils/xx.js
,现在只需要写@/utils/xx.js
,至于配置的层级,怎么方便怎么来
alias:{
"@":path.resolve(__dirname,"./src")
}
看到这里其实已经可以对webpack
有一定的认识,回头看那些vue
,react
的脚手架相信就不会再陌生
完:)
转载自:https://juejin.cn/post/7165752520919220255