从头搭建一个基于webpack的项目

news2024/11/18 9:22:41

从头搭建一个基于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,因此,我们将上述 htmlwebpack.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。

在这里插入图片描述

添加字体文件并引用测试

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hi5o9R4Q-1690792169175)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230726150819606.png)]

参考链接: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.csssrc/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如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v1w16c1q-1690792169178)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230730095525826.png)]

在这里插入图片描述

  • 查看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、打包查看输出

  • 源代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CkFAFVbz-1690792169179)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230730113843366.png)]

  • 打包后代码

在这里插入图片描述

参考链接:https://webpack.js.org/loaders/babel-loader/#install

十一、JS压缩TerserWebpackPlugin

webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin

按照官网的说法,我们实际上不需要去进行特殊的配置了,但是我们在配置CSS代码压缩时有主意到:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oama1t5J-1690792169179)(/Users/liangchenyang/Documents/Web/Vue模板项目(脚手架)/从头搭建一个基于webpack的Vue3项目.assets/image-20230730115522064.png)]

因此,我们修改webpack配置如下:

在这里插入图片描述

十二、图片压缩

图片压缩分为无损压缩有损压缩,它们共同要使用的包是:image-minimizer-webpack-pluginimagemin

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 将按照默认条件,自动地在 resourceinline 之间进行选择:小于 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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/921178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一篇文章告诉你,为什么要使用Javascript流程图来可视化进程?(下)

DHTMLX Diagram库是有各种类型的图组成的&#xff0c;其中最广泛使用的是JavaScript流程图&#xff0c;它可以显示任何类型的的工作流、过程或系统&#xff0c;您可以下载DHTMLX Diagram的评估版并亲自试用。 在上文中&#xff08;点击这里回顾>>&#xff09;&#xff0…

Python标准库概览

Python标准库概览 知识点 标准库: turtle库(必选)标准库: random库(必选)、time库(可选&#xff09; 知识导图 1、turtle库概述 turtle&#xff08;海龟&#xff09;是Python重要的标准库之一&#xff0c;它能够进行基本的图形绘制。turtle库绘制图形有一个基本框架&#x…

ubuntu18.04复现yolo v8之最终章,realsenseD435i+yolo v8完美运行

背景&#xff1a;上一篇博客我们已经为复现yolov8配置好了环境&#xff0c;如果前面的工作顺利进行&#xff0c;我们已经完成了90%&#xff08;学习类程序最难的是环境配置&#xff09;。 接下来将正式下载yolov8的相关代码&#xff0c;以及进行realsenseD435i相机yolo v8的de…

ONLYOFFICE 文档如何与 Alfresco 进行集成

ONLYOFFICE 文档是一款开源办公套件&#xff0c;其是包含文本文档、电子表格、演示文稿、数字表单、PDF 查看器和转换工具的协作性编辑工具。要在 Alfresco 中使用 ONLYOFFICE 协作功能&#xff0c;可以将他们连接集成。阅读本文&#xff0c;了解这如何实现。 关于 ONLYOFFICE…

长胜证券:逾九成北交所公司上半年盈利,两大板块表现优异

到现在&#xff0c;已有28家北交所公司净赢利增速超越30%。 逾九成北交所公司完成盈余 半年报进入密布发表期。证券时报数据宝统计&#xff0c;到8月23日收盘&#xff0c;已有88家北交所上市公司发布2023年半年度相关陈述。 从营收规模来看&#xff0c;合计69家北交所公司上半…

传感器IMU

IMU根据其属性&#xff0c;可以知道其主要测量是线加速度和角加速度&#xff1a; (1) (2) 其中和分别是线加速度偏差和角加速度偏差,可以利用随机游走模型建模&#xff0c;, ,且符合高斯分布;和是噪声&#xff0c;一般认为符合高斯分布;表示全球坐标下的重力加速度;表示旋转变…

网络电子词典

一、项目要求&#xff1a; 1. 登录注册功能&#xff0c;不能重复登录&#xff0c;重复注册 2. 单词查询功能 3. 历史记录功能&#xff0c;存储单词&#xff0c;意思&#xff0c;以及查询时间 4. 基于TCP&#xff0c;支持多客户端连接 5. 采用数据库保存用户信息与历史记录…

002 编程是什么?

魔法师:在这个充满魔法和奇迹的数字时代,你是否好奇过计算机是如何运作的?当你用手机玩游戏、在电脑上浏览网页、看动画电影,你是否想过这背后的秘密是什么?别担心,今天我们将揭开这神秘的面纱,一起来探索编程的神奇世界! 编程,简单地说,就是一种让计算机执行任务的…

第五章:认证和动态菜单功能【基于Servlet+JSP的图书管理系统】

一、登录功能 1.认证实现 53-图书管理系统-登录功能-认证处理 首先完成最基础的登录功能&#xff0c;也就是在登录页面通过表单提交账号和密码到Servlet中。做相关的校验。给出不同的反应。 然后对应的Servlet中的处理逻辑 WebServlet(name "loginServlet",urlPatt…

软件测试的常用概念

目录 需求 需求和软件测试人员的关系 需求是侧式人员进行软件测试工作的依据,需要通过软件需求,来设计测试用例 软件的生命周期 在每个阶段,测试人员需要做什么事? 软件测试的生命周期 BUG 什么是bug? 如何描述一个bug? bug的级别 bug的生命周期: 调试和测试的区…

Linux虚拟机安装(Ubuntu 20)

最近这段时间使用VMWare安装了一下Ubuntu版本的Linux虚拟机&#xff0c;在这里记录一下安装时参考的文章以及需要注意的细节 参考链接&#xff1a; 虚拟机&#xff08;VMware&#xff09;安装Linux&#xff08;Ubuntu&#xff09;安装教程 VMware虚拟机下安装Ubuntu20.04&…

这所985重大科目变更!新增专硕可考信号!

一、学校及专业介绍 重庆大学&#xff08;ChongqingUniversity&#xff0c;CQU&#xff09;&#xff0c;简称“重大”&#xff0c;是教育部直属的全国重点大学&#xff0c;是国家“211工程”和“985工程”重点建设的高水平研究型综合性大学、国家“世界一流大学建设高校&#…

跨境电商系统开发:打破国界壁垒,拓展全球市场

拓展全球市场的必然选择 随着国际贸易水平的不断提升和全球市场的日益开放&#xff0c;跨境电商作为一种高效的贸易模式&#xff0c;受到了越来越多电商企业的关注和青睐。跨境电商不仅可以打破国界壁垒和时差限制&#xff0c;还可以在全球市场上实现销售的拓展&#xff0c;带来…

SVN 项目管理笔记

SVN 项目管理笔记 主要是介绍 SVN 管理项目的常用操作&#xff0c;方便以后查阅&#xff01;&#xff01;&#xff01; 一、本地项目提交到SVN流程 在SVN仓库下创建和项目名同样的文件夹目录&#xff1b;选中本地项目文件&#xff0c;选择SVN->checkout,第一个是远程仓库项…

FOC之SVPWM学习笔记

一、参考资料 【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术 - 知乎FOC入门教程_zheng是在下的博客-CSDN博客DengFOC官方文档技术干货 |【自制】FOC驱动板 二、FOC控制算法流程框图 在FOC控制中主要用到三个PID环&#xff0c;从内到外依次是&#xff1a;电流环、速度环、位…

DevExpress WinForms数据编辑器组件,提供丰富的数据输入样式!(二)

DevExpress WinForms超过80个高影响力的WinForms编辑器和多用途控件&#xff0c;从屏蔽数据输入和内置数据验证到HTML格式化&#xff0c;DevExpress数据编辑库提供了无与伦比的数据编辑选项&#xff0c;包括用于独立数据编辑或用于容器控件(如Grid, TreeList和Ribbon)的单元格。…

第60步 深度学习图像识别:误判病例分析(Pytorch)

基于WIN10的64位系统演示 一、写在前面 上期内容基于Tensorflow环境做了误判病例分析&#xff08;传送门&#xff09;&#xff0c;考虑到不少模型在Tensorflow环境没有迁移学习的预训练模型&#xff0c;因此有必要在Pytorch环境也搞搞误判病例分析。 本期以SqueezeNet模型为…

Java不用加减乘除做加法(图文详解)

目录 1.题目描述 2.题解 分析 具体实现 1.题目描述 写一个函数&#xff0c;求两个整数之和&#xff0c;要求在函数体内不得使用、-、*、/四则运算符号。 示例 输入&#xff1a;1 2 输出&#xff1a;3 2.题解 分析 不能使用加减乘除四则运算符&#xff0c;那我们只能考虑…

论文笔记:从不平衡数据流中学习的综述: 分类、挑战、实证研究和可重复的实验框架

0 摘要 论文&#xff1a;A survey on learning from imbalanced data streams: taxonomy, challenges, empirical study, and reproducible experimental framework 发表&#xff1a;2023年发表在Machine Learning上。 源代码&#xff1a;https://github.com/canoalberto/imba…

多环境开发

多环境 1、多环境开发&#xff08;YAML版&#xff09; 小结&#xff1a; 多环境开发需要设置若干种常用环境&#xff0c;例如开发、生产、测试环境yaml格式中设置多环境使用—区分环境设置边界每种环境的区别在于加载的配置属性不同启用某种环境时需要指定启动时使用该环境 …