从头搭建一个基于webpack的项目
一、起步
1、创建目录,初始化npm,安装webpack
mkdir vue3-spa-template
cd vue3-spa-template
npm init -y
npm install webpack webpack-cli --save-dev
备注:在安装一个 package时,此 package 要打包到生产环境中时,你应该使用
npm install --save
。此package只用于开发环境时(例如,linter, 测试库等),你应该使用npm install --save-dev
2、添加README.md,为项目添加必要说明
3、创建第一个bundle
- 安装lodash库:
npm install --save lodash
- 添加dist/index.js和src/index.html
备注:执行
npx webpack
,会将我们的脚本src/index.js
作为 入口起点,会生成dist/main.js
作为 输出,所以我们index.html模板这里的js路径要先写成main.js。
- 执行
npx webpack
,会在dist文件夹下生成打包的main.js文件,在浏览器中打开index.html如下所示。
4、创建webpack的配置文件webpack.config.js
- 添加build/webpack.config.js,并初始化基本配置
- 执行
npx webpack --config ./build/webpack.config.js
后效果和第3步手动执行的结果一样,生成main.js 。
5、添加npm script
输入一大段字符来运行webpack打包程序无疑是繁琐的,所以我们在package.json中配置script脚本如下,这样我们就可以使用
npm run build
来执行打包动作了
参考链接:https://webpack.docschina.org/guides/getting-started/
二、管理资源
1、跟随主流
前端主流做法是将输出的打包文件命名为
bundle
,因此,我们将上述html
及webpack.config.js
中的main.js
更名为bundle.js
2、CSS文件加载
为了在 JavaScript 模块中 import
一个 CSS 文件,你需要安装 style-loader 和 css-loader,并在 module
配置 中添加这些 loader。
npm install style-loader css-loader --save-dev
备注:应保证 loader 的先后顺序:
'style-loader'
在前,而'css-loader'
在后。
- 添加用于测试的样式文件
备注:这里css样式文件会被打包到bundle.js中,而不是插入到index.html中
3、加载图片资源
在 webpack 5 中,可以使用内置的资源模块( Asset Modules),它是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。
在 webpack 5 之前,通常使用:
raw-loader
将文件导入为字符串url-loader
将文件作为 data URI 内联到 bundle 中file-loader
将文件发送到输出目录资源模块类型(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
,并且配置资源体积限制实现。
修改index.js测试打包后结果:
4、加载字体文件
字体文件的加载同图片资源一样,同样使用内置的资源模块( Asset Modules)进行加载,无需额外配置loader。
添加字体文件并引用测试
参考链接:https://webpack.docschina.org/guides/asset-management/
三、管理输出
到目前为止,我们都是在
index.html
文件中手动引入所有资源,然而随着应用程序的不断增长,一旦开始 使用哈希值进行文件命名 并输出 多个 bundle,手动管理index.html
文件将变得困难。然而,使用一些插件可以让这个过程更容易管理。
1、设置html模板(htmlwebpackplugin)
- 安装htmlwebpackplugin
npm install --save-dev html-webpack-plugin
- 添加public文件夹,里面放入favicon.ico图标文件和index.html模版,index.html模版如下图所示:
- 调整
build/webpack.config.js
文件,利用public文件夹下的内容通过配制自动生成dist/index.html模版:
2、自动清理dist文件夹
你可能已经注意到,由于遗留了之前的指南的代码示例,
/dist
文件夹显得相当杂乱。webpack 将生成文件并放置在/dist
文件夹中,但是它不会追踪哪些文件是实际在项目中用到的。通常比较推荐的做法是,在每次构建前清理
/dist
文件夹,这样只会生成用到的文件。可以使用output.clean
配置项实现这个需求。
参考链接:https://webpack.docschina.org/guides/output-management/
四、开发环境
1、添加 mode
区分开发环境 development
和 生产环境 production
2、使用source-map
当 webpack 打包源代码时,可能会很难追踪到 error(错误)和 warning(警告)在源代码中的原始位置。
为了更容易地追踪 error 和 warning,JavaScript 提供了 source map 功能,可以将编译后的代码映射回原始源代码。source map 会直接告诉你错误来源于哪一个源代码。
可用选项参考:https://webpack.docschina.org/configuration/devtool
3、热更新:webpack-dev-server
webpack-dev-server
提供了一个基本的 web server,并具有实时重新加载的功能。更多配置文档:https://webpack.docschina.org/configuration/dev-server
- 安装
webpack-dev-server
npm install --save-dev webpack-dev-server
- 修改
webpack.config.js
- 添加npm script
此时可以直接运行 npm run dev
开发需求了,并且在每一次代码变更后都会自动重新编译
参考链接:https://webpack.docschina.org/guides/development/
五、代码分离、bundle分析
1、代码分离
SplitChunksPlugin
插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。
- 改造build/webpack.config.js文件,创建多入口(每个入口中都引入并使用lodash)
- 分离前后打包文件大小对比
2、bundle分析
一旦开始分离代码,一件很有帮助的事情是,分析输出结果来检查模块在何处结束。webpack-bundle-analyzer:一个 plugin 和 CLI 工具,它将 bundle 内容展示为一个便捷的、交互式、可缩放的树状图形式。我们利用该插件分析打包情况。
- 安装插件
npm install --save-dev webpack-bundle-analyzer
- 修改
build/webpack.config.js
,添加插件配置
- 在浏览器查看分析结果
参考链接:https://webpack.docschina.org/guides/code-splitting/
六、环境变量
随着webpack.js的配置越来越多,有些配置我们希望只在开发环境上生效,有些配置我们希望只在生产环境上生效,所以是时候引入环境变量进行控制了。
1、安装cross-env,package.json中添加NODE_ENV变量进行环境控制
cross-env:它是运行跨平台设置和使用环境变量的脚本(解决了,使用NODE_ENV =production, 来设置环境变量时windows环境下报错的问题)
- 安装cross-env
npm install --save-dev cross-env
- 修改package.json中的script命令
2、使用环境变量(webpack.config.js)
七、缓存
通过配置确保 webpack 编译生成的文件在没有改变时能够被客户端缓存,而在文件内容变化后,又能够请求到新的文件。
1、[contenthash]
[contenthash]
将根据资源内容创建唯一哈希值。当资源内容发生变化时,[contenthash]
也会发生变化。
- 修改build/webpack.config.js,添加
contenthash
并截取保留8位
- 查看打包结果
- 问题(特别注意:按我们的理解,我现在现在什么都不修改,再次npm run build时hash值应该不会变化,但受webpack版本的影响,有时会发现即使内容没有改变,只要重新编译就会生成不同的hash值(当前版本5.88.2没有遇到此问题)
按照官网提示,以防万一的情况,我们配置
引导提取模板
来规避上述问题
2、引导提取模板
正如我们在 代码分离 中所学到的,
SplitChunksPlugin
可以用于将模块分离到单独的 bundle 中。webpack 还提供了一个优化功能,可以使用optimization.runtimeChunk
选项将 runtime 代码拆分为一个单独的 chunk。将其设置为single
以为所有 chunk 创建一个 runtime bundle实际上前边为了看到打包前后文件体积大小的差异,我们进行了多入口的实验
- 修改配置项
- 打包查看输出结果,如果引导文件被打包生成:
-
将第三方库(library)(例如
lodash
或 vue)提取到单独的vendor
chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。通过SplitChunksPlugin
插件的cacheGroups
选项来实现抽取,现修改build/webpack.config.js文件如下: -
执行
npm run build
后会将以使用的lodash抽取到vendors.hash.bundle.js
中
参考链接:https://webpack.docschina.org/guides/caching/
八、处理less文件、兼容性处理
实际开发过程中我们通常是使用css预处理器来书写css样式
1、处理less文件
- 安装sass
npm install less less-loader --save-dev
- 修改
build/webpack.config.js
文件如下:
- 修改原
src/style.css
为src/style.less
,并在修改引用后进行build
2、PostCSS自动补全浏览器前缀
在编写css样式的时候,浏览器的兼容性是我们应该考虑的一个问题,为此我们使用postcss、postcss-loader、 postcss-preset-env进行样式兼容处理。
- 安装(webpack5中不需要安装postcss-preset-env)
npm install --save-dev postcss-loader postcss postcss-preset-env
- 修改
webpack.config.js
如下:
- 添加使用 PostCSS 本身的 配置文件:
- 添加.browserslistrc文件如下,兼容使用率大于0.2%的浏览器,同时官方没有超过24个月不维护的浏览器。
- 添加样式属性打包测试
参考链接:
https://webpack.docschina.org/loaders/less-loader/
https://webpack.docschina.org/loaders/postcss-loader/
九、提取、优化、压缩CSS
1、清理无用文件
- 移除another-module相关配置,改回单入口配置,减少生成的文件
- 直到目前为止,css的样式还是被打在了index.hash.bundle.js当中,没有被单独的抽取出来,从下边两图中可以看出:
2、使用MiniCssExtractPlugin剥离CSS文件
本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
本插件基于 webpack v5 的新特性构建,并且需要 webpack 5 才能正常工作。
- 安装
npm install --save-dev mini-css-extract-plugin
- 修改webpack.config.js如下:
- 查看build效果
3、使用CssMinimizerWebpackPlugin优化和压缩CSS
- 安装
npm install css-minimizer-webpack-plugin --save-dev
- 修改webpack配置如下:
- 再度build查看:
参考链接:
https://webpack.docschina.org/plugins/mini-css-extract-plugin/
https://webpack.docschina.org/plugins/css-minimizer-webpack-plugin/
十、配置babel将ES6语法解析为ES5
1、基础配置
- 安装
npm install -D babel-loader @babel/core @babel/preset-env
npm install -D @babel/plugin-transform-runtime
- @babel/plugin-transform-runtime的作用:
Babel 在每个文件都插入了辅助代码,使代码体积过大
Babel 对一些公共方法使用了非常小的辅助代码,比如
_extend
。默认情况下会被添加到每一个需要它的文件中。你可以引入 Babel runtime 作为一个独立模块,来避免重复引入。
- 修改webpack配置如下:
- 添加babel.config.js
2、某些ES6语法未被转化为ES5问题
以下版本:默认情况下,Webpack假定你的目标环境支持ES2015的一些特性
“@babel/core”: “^7.22.9”,
“@babel/plugin-transform-runtime”: “^7.22.9”,
“@babel/preset-env”: “^7.22.9”,
“babel-loader”: “^9.1.3”,
“webpack”: “^5.88.2”,
“webpack-bundle-analyzer”: “^4.9.0”,
“webpack-cli”: “^5.1.4”,
“webpack-dev-server”: “^4.15.1”
-
方式一:当前版本下,webpack5配置babel将不会转换箭头函数语法、const语法等ES6语法(默认targets为default)
需要显式设置targets: 'ie 11’等,才会转化为ES5语法
- 方式二:指定输出
例:如果你不想要箭头函数,那么就这样做
// webpack.config.js
module.exports = {
// ...
output: {
// ...
environment: {
// ...
arrowFunction: false, // 不要输出箭头函数
},
},
};
3、打包查看输出
- 源代码
- 打包后代码
参考链接:https://webpack.js.org/loaders/babel-loader/#install
十一、JS压缩TerserWebpackPlugin
webpack v5 开箱即带有最新版本的
terser-webpack-plugin
。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装terser-webpack-plugin
。
按照官网的说法,我们实际上不需要去进行特殊的配置了,但是我们在配置CSS代码压缩时有主意到:
因此,我们修改webpack配置如下:
十二、图片压缩
图片压缩分为无损压缩
和有损压缩
,它们共同要使用的包是:image-minimizer-webpack-plugin
和 imagemin
npm install image-minimizer-webpack-plugin imagemin --save-dev
1、无损压缩
- 安装所需包
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
- 修改webpack配置
- 添加一个大图片(仅测试用)
- 使用图片压缩前文件大小及打包速度
- 使用无损压缩优化图片
2、有损压缩
- 安装包
npm install @squoosh/lib --save-dev
- 修改webpack配置
- build查看打包后文件大小及打包时长
3、总结
我们通过以上实验发现,在压缩图片后确实可以达到减少 文件大小
的目的,但是也有相应的弊端:打包 时长过长
,因此,在使用时要根据实际情况来抉择。
参考链接:https://webpack.js.org/plugins/image-minimizer-webpack-plugin/
十二、添加@路径解析、配置jsconfig.json解决resolve.alias跳转问题
1、配置路径别名、添加顺序解析:尝试按顺序解析后缀名
- 修改webpack配置
2、使用路径别名添加编辑器提示
- 添加jsconfig.json文件对相关路径别名进行配置
3、测试
十三、一些小的优化点
1、指定资源输出目录
2、优化图片小于10kb使用base64来处理
现在,webpack 将按照默认条件,自动地在
resource
和inline
之间进行选择:小于 8kb 的文件,将会视为inline
模块类型,否则会被视为resource
模块类型。(type需要设置为:asset,不能指定为asset/resouce)可以通过在 webpack 配置的 module rule 层级中,设置
Rule.parser.dataUrlCondition.maxSize
选项来修改此条件:
- 引入一个9k的图片资源
- 修改webpack配置
十四、这是一个阶段性成果,到目前为止,以上的所有配置不仅可以搭配vue使用,也可以搭配其它框架,如:react;下一阶段的配置属于大同小异,基本只需要替换vue相关的配置即可。
十五、加入Vue全家桶
1、让webpack能编译.vue文件
- 安装vue-loader
npm install vue-loader -D
- 修改webpack配置
2、加入Vue全家桶(vue3、vue-router、pinia、elementPlus)
- 安装
npm install vue vue-router vuex element-plus --save
2.1、新建App.vue,修改src/index.js引入vue。
// src/index.js
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
console.log(app);
app.mount("#app");
// src/App.vue
<script setup>
import { ref } from "vue";
const welcome = ref("Hello vue");
</script>
<template>
<div>{{ welcome }}</div>
</template>
<style lang="less" scoped></style>
2.2、引入vue-router,新建src/router/index.js,新建Home.vue,修改App.vue
// src/index.js
import { createApp } from "vue";
import router from "./router";
import App from "./App.vue";
const app = createApp(App);
app.use(router);
app.mount("#app");
// src/router/index.js
const { createRouter, createWebHashHistory } = require("vue-router");
const routes = [
{
path: "/home",
name: "Home",
component: () => import("../views/Home.vue"),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
<!-- src/views/Home.vue -->
<script setup></script>
<template>
<div class="home">Home Page</div>
</template>
<style lang="less" scoped>
.home {
height: 50px;
width: 50px;
background-color: aquamarine;
}
</style>
<!-- src/App.vue -->
<script setup>
import { ref } from "vue";
const welcome = ref("Hello vue");
</script>
<template>
<div>{{ welcome }}</div>
<RouterLink to="/home">Home</RouterLink>
</template>
<style lang="less" scoped></style>
2.3、引入并使用pinia
- 修改src/index.js
// src/index.js
import { createApp } from "vue";
import router from "./router/index";
import App from "./App.vue";
import { createPinia } from "pinia";
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount("#app");
- 新建文件src/store/index.js
import { defineStore } from "pinia";
// 第一个参数是应用程序中 store 的唯一 id
export const useUser = defineStore("useUser", {
state: () => {
return {
age: 18,
name: "小华",
};
},
getters: {
// 自动将返回类型推断为数字
fatherAge(state) {
return state.age + 18;
},
},
// 相当于vue中的methods,可以是异步的
actions: {
addUserAge() {
this.age++;
},
},
});
- 修改src/App.vue
<!-- src/App.vue -->
<script setup>
import { useUser } from "@/stores/index";
import { storeToRefs } from "pinia"; // 保持响应式
import { ref } from "vue";
const welcome = ref("Hello vue");
const user = useUser();
// 默认情况下,您可以通过 store 实例访问状态来直接读取和写入状态:
const addUserAge = () => {
// 方式一:非解构修改数据
// user.age++;
// 方式二:非解构修改数据
user.$patch(state => {
state.age += 1;
});
};
</script>
<template>
<div>{{ welcome }}</div>
<RouterLink to="/home">Home {{ user.name }} {{ user.age }}</RouterLink>
<button @click="addUserAge">过生日</button>
<RouterView></RouterView>
</template>
<style lang="less" scoped></style>
- 修改src/views/Home.vue
<script setup>
import { useUser } from "@/stores/index";
import { storeToRefs } from "pinia"; // 保持响应式
const user = useUser();
// // 解构时,必须要storeToRefs
const { name, age, fatherAge } = storeToRefs(user);
// 默认情况下,您可以通过 store 实例访问状态来直接读取和写入状态:
const addUserAge = () => {
age.value++;
};
console.log(name, age);
</script>
<template>
<div class="home">
<span>Home Page</span>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<div>父亲年龄:{{ fatherAge }}</div>
<button @click="addUserAge">过生日</button>
<button @click="user.addUserAge()">调用actions</button>
</div>
</template>
<style lang="less" scoped>
.home {
width: 200px;
background-color: aquamarine;
}
</style>
2.4、引入elementPlus
- 自动按需导入
npm install -D unplugin-vue-components unplugin-auto-import
- 修改webpack配置
// webpack.config.js
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
// ...
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}
- 修改src/index.js
// src/index.js
import { createApp } from "vue";
import router from "./router/index";
import App from "./App.vue";
import { createPinia } from "pinia";
import ElementPlus from "element-plus";
const app = createApp(App);
app.use(createPinia());
app.use(ElementPlus, { size: "middle", zIndex: 3000 });
app.use(router);
app.mount("#app");
3、处理控制台警告
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKrEkCKO-1690792169180)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230731141103144.png)]
const webpack = require("webpack");
module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
// 解决浏览器报的warning
__VUE_OPTIONS_API__: true, // 是否支持vue2的optionsAPI
__VUE_PROD_DEVTOOLS__: false, // 开发阶段tree shaking
}),
],
}
十六、实现pinia数据持久化
1、自己编写插件实现
2、使用第三方插件
- 安装
npm i pinia-plugin-persistedstate -D
- 修改src/index.js
// src/index.js
import { createApp } from "vue";
import router from "./router/index";
import App from "./App.vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import ElementPlus from "element-plus";
const app = createApp(App);
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
app.use(pinia);
app.use(ElementPlus, { size: "middle", zIndex: 3000 });
app.use(router);
app.mount("#app");
- 修改src/stores/index.js
import { defineStore } from "pinia";
// 第一个参数是应用程序中 store 的唯一 id
export const useUser = defineStore("useUser", {
state: () => {
return {
age: 18,
name: "小华",
};
},
getters: {
// 自动将返回类型推断为数字
fatherAge(state) {
return state.age + 18;
},
},
// 相当于vue中的methods,可以是异步的
actions: {
addUserAge() {
this.age++;
},
},
// 持久化具体配置查看:https://prazdevs.github.io/pinia-plugin-persistedstate/guide/
persist: {
storage: sessionStorage, // 默认被存储在localstorage中
},
});
十七、eslint&prettier进行js(ts vue)文件规范检查
- 为vscode安装eslint插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cAdNrYT-1690792169180)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230731151144349.png)]
- 为vscode安装Prettier插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JQ1iFscp-1690792169180)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230731154858432.png)]
- 安装eslint包
npm install eslint -D
- 安装eslint-config-airbnb-base
npx install-peerdeps --dev eslint-config-airbnb-base
- 安装eslint-plugin-vue
npm install --save-dev eslint-plugin-vue
- 安装prettier和eslint-config-prettier
npm install prettier eslint-config-prettier -D
- 安装
eslint-plugin-prettier
npm install --save-dev eslint-plugin-prettier
- 添加.eslintrc.js
// 解决代码中存在的问题避免错误
module.exports = {
// 规则到此不往上找
root: true,
// env环境设置,预定义全局变量,这些环境并不是互斥的,所以你可以同时定义多个
env: {
browser: true,
node: true,
es2021: true,
},
// 扩展风格,extends属性值可以省略包名的前缀 eslint-config-
extends: [
'plugin:vue/vue3-essential',
'airbnb-base',
// 'prettier', // eslint-config-prettier 来关掉 (disable) 所有和 Prettier 冲突的 ESLint 的配置,prettier 一定要是最后一个,才能确保覆盖
'plugin:prettier/recommended', // 同时使用了 eslint-plugin-prettier 和 eslint-config-prettier 可以这么配置
],
settings: {
'import/resolver': { webpack: { config: 'build/webpack.config.js' } },
},
// 针对个别文件设置新的检查规则
// 要为特定类型的文件指定处理器,请使用 overrides 键和 processor 键的组合
// 若要禁用一组文件的配置文件中的规则,请使用 overrides 和 files
overrides: [],
parserOptions: {
// 指定要使用的 ECMAScript 版本
ecmaVersion: 'latest',
// 设置为 script (默认) 或 module(如果你的代码是 ECMAScript 模块)
sourceType: 'module',
},
// 插件名称可以省略 eslint-plugin- 前缀。插件可以处理除js外的别的文件格式,引入插件的目的就是为了增强 ESLint 的检查能力和范围。
plugins: ['vue', 'prettier'],
// 规则列表
rules: {
// 提醒你不要直接修改函数的入参,为这个规则添加一个白名单,即指定的入参名称不予限制
// 'no-param-reassign': [
// 'error',
// {
// props: true,
// ignorePropertyModificationsFor: [
// 'e', // for e.returnvalue
// 'ctx', // for Koa routing
// 'req', // for Express requests
// 'request', // for Express requests
// 'res', // for Express responses
// 'response', // for Express responses
// 'state', // for vuex state
// ],
// },
// ],
// 提醒你不要直接修改函数的入参
'no-param-reassign': 0,
// .vue文件必须是多个字符
'vue/multi-word-component-names': 0,
// 禁止变量声明覆盖外层作用域的变量
'no-shadow': ['error', { allow: ['state', 'getters'] }],
},
}
- 添加.eslintignore
# ESLint 总是忽略 /node_modules/ 和 /bower_components/ 中的文件;
# 因此对于一些目前解决不了的规则报错,但是如果又急于打包上线,在不影响运行的情况下,我们就可以利用 .eslintignore 文件将其暂时忽略。
#本地查看dist时,eslint不需要检查
dist
- 添加.vscode/setting.json
{
"editor.formatOnSave": false,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.alwaysShowStatus": true
}
- 添加.prettierignore
**/*.svg
node_modules
dist
- 添加.prettierrc.js
//Prettier 支持可以配置参数不多,2022.12.1日查看时,总共才 21 个,这里是所有参数的说明 prettier options
//参考地址:https://prettier.io/docs/en/options.html#print-width
//该文件修改,要重新启动vscode才能生效,否则不生效
//解决代码风格的的问题
module.exports = {
printWidth: 120, //(默认值)单行代码超出 80 个字符自动换行
tabWidth: 4, //默认一个 tab 键缩进相当于 2 个空格
useTabs: true, // 行缩进使用 tab 键代替空格
semi: false, //(默认值)语句的末尾加上分号
singleQuote: true, // 使用单引号
quoteProps: 'as-needed', //(默认值)仅仅当必须的时候才会加上双引号
jsxSingleQuote: true, // 在 JSX 中使用单引号
trailingComma: 'all', // 不用在多行的逗号分隔的句法结构的最后一行的末尾加上逗号
bracketSpacing: true, //(默认值)在括号和对象的文字之间加上一个空格
bracketSameLine: false, // (默认值)元素的 > 单独占一行
arrowParens: 'avoid', // 当箭头函数中只有一个参数的时候可以忽略括弧
htmlWhitespaceSensitivity: 'ignore', // vue template 中的结束标签结尾尖括号掉到了下一行
vueIndentScriptAndStyle: false, //(默认值)对于 .vue 文件,不缩进 <script> 和 <style> 里的内容
endOfLine: 'lf', //(默认值) Linux and macOS as well as inside git repos
// endOfLine:'crlf', //(默认值) Linux and macOS as well as inside git repos
embeddedLanguageFormatting: 'auto', //(默认值)允许自动格式化内嵌的代码块
}
- 此时发现会有eslint报错提示了,但是会有报错:Unable to resolve path to module ‘vue’ 等…
npm i eslint-import-resolver-webpack -D
- 此时很多文件第一行还会有一个报错:Resolve error: unable to load resolver “alias”
npm install eslint-import-resolver-alias -D
十八、工程目录结构整理,webpack.config整理
1、目录整理
2、webpack.config.js整理
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const appHtml = path.resolve(__dirname, '../public/index.html')
// 本插件会提取css到单独的文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 此插件用于优化和压缩CSS
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
// const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const { VueLoaderPlugin } = require('vue-loader')
// elementPlus自动导入相关配置
// eslint-disable-next-line import/no-unresolved
const AutoImport = require('unplugin-auto-import/webpack')
// eslint-disable-next-line import/no-unresolved
const Components = require('unplugin-vue-components/webpack')
// eslint-disable-next-line import/no-unresolved
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
let isProd = true
function getWebpackConfig() {
isProd = process.env.NODE_ENV === 'production'
return {
mode: isProd ? 'production' : 'development',
devtool: isProd ? 'source-map' : 'eval-source-map', // 可用选项参考:https://webpack.docschina.org/configuration/devtool
entry: {
index: './src/main.js',
},
output: {
filename: '[name].[contenthash:8].js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/', // 发送到 output.path 目录的每个文件,都将从 output.publicPath 位置引用
clean: true, // 每次构建前清理 /dist 文件夹
},
// 如果想要在一个 HTML 页面上使用多个入口,还需设置 optimization.runtimeChunk: 'single'
// // 将包含chunks映射关系的list单独从入口文件里提取出来,方便浏览器缓存,否则会在入口文件js中每次都会发生变化,所有的入口文件一起共同生成一个runtimeChunk。
optimization: {
minimize: isProd, // 如果是ture会进行js、css压缩,会产生LICENSE.txt文件,把注释提取到单独的txt文件中
// 压缩CSS
// 这将仅在生产环境开启 CSS 优化。如果还想在开发环境下启用 CSS 优化,请将 optimization.minimize 设置为 true
minimizer: [
// js的压缩全靠这三个...,webpack认为,如果配置了minimizer,就表示开发者在自定义压缩插件,无论配置minimizer是true还是false,内部的JS压缩器都会被覆盖掉。所以我们这里要手动把它加回来,webpack内部使用的JS压缩器是terser-webpack-plugin.
`...`,
new CssMinimizerPlugin(),
],
// chunk分离
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
// 告诉 webpack 忽略 splitChunks.minSize、splitChunks.minChunks、splitChunks.maxAsyncRequests 和 splitChunks.maxInitialRequests 选项,并始终为此缓存组创建 chunk。
enforce: true,
},
},
},
runtimeChunk: 'single',
},
resolve: {
// import引入文件的时候不用加后缀,webpack会自动按顺序尝试解析
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
// 路径别名
alias: { '@': path.resolve(__dirname, '../src') },
},
// 更多配置文档:https://webpack.docschina.org/configuration/dev-server
devServer: {
static: {
directory: path.join(__dirname, '../dist'),
},
client: {
progress: true,
},
compress: true, // 启用 gzip compression:
historyApiFallback: true,
hot: true,
open: true, // 自动打开浏览器
port: 'auto', // 自动使用一个可用端口
proxy: {
'/api': {
target: 'http://cf-pc-dev.wti-xa.com:7777',
changeOrigin: true, // 设置为true, 本地就会虚拟一个服务器接收你的请求并代你发送该请求,主要解决跨域问题
pathRewrite: {
// '^/api': ''
},
},
},
// 默认情况下,开发服务器将通过 HTTP 提供服务。可以选择使用 HTTPS 提供服务:
// https: true,
},
module: {
rules: [
{
test: /\.css$/i,
use: [
// 不要同时使用* `style-loader` *与* `mini-css-extract-plugin`*。*
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
],
},
{
test: /\.less$/i,
use: [
// compiles Less to CSS
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
'less-loader',
],
},
{
test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,
type: 'asset',
// 不配置的情况下,webpack会把8k以下的文件转换成base64的URL
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 4kb
},
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
exclude: /(node_modules)/,
// include: path.resolve(__dirname, '../src'),
use: {
loader: 'babel-loader',
options: {
cacheDirectory: !isProd, // 使用 cacheDirectory 选项,将 babel-loader 提速至少两倍。这会将转译的结果缓存到文件系统中。
// presets: [["@babel/preset-env", { targets: "ie 11" }]],
// plugins: ["@babel/plugin-transform-runtime"],
// 上边两项配置移动到babel.config.js
},
},
},
{
test: /\.vue$/,
use: 'vue-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'Vue3+webpack5系统框架',
template: appHtml,
favicon: path.resolve(__dirname, '../public/favicon.ico'),
// 附加一个唯一的webpack编译散列到所有包含的脚本和CSS文件。这对缓存破坏很有用
// 这里所有的引用都用一个hash值每次都会所有的都发生改变,所以用output的[contenthash]hash来替换这里。
// hash: true,
xhtml: true, // 如果为true,则将链接标记呈现为自关闭(符合XHTML)
}),
// 打包分析工具
isProd &&
new BundleAnalyzerPlugin({
analyzerMode: 'static', // 生成一个分析报告的html文件(默认生成一个 report.html)
openAnalyzer: false, // 默认值为true,是否在浏览器中自动打开报表
}),
// 提取CSS文件
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
}),
new VueLoaderPlugin(),
// elementPlus自动导入相关配置
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
new webpack.DefinePlugin({
// 解决浏览器报的warning
__VUE_OPTIONS_API__: true, // 是否支持vue2的optionsAPI
__VUE_PROD_DEVTOOLS__: false, // 开发阶段tree shaking
}),
].filter(Boolean), // 去掉假值
}
}
module.exports = getWebpackConfig()