Skip to content
On this page

Dev环境用vite替换webpack获得极致开发体验🥰

背景

可能你会好奇的问:“我项目已用webpack配置开发和生产环境打包,好好的为啥我要切换呢?”。有这么一种情况你肯定也碰到过,在开发中需要修改某个组件,搜索时发现很多个相同名组件,但是属于不同的目录,这时你很难确定用的是哪个组件?

Untitled

想到解决方案

  • 方案一:严格规定项目中每个名字独立无二(不靠谱,不管单人还是多人都很难保证名字不重复)
  • 方案二:利用vite-plugin-vue-inspector插件(当前非常流行的方案)

此时也面临一个问题,由于项目是基于webpack来构建的,网络上搜索了一大圈都没有找到webpack-plugin-vue-inspector 的东西,所以接下来只有两条路走。

  • 第一条路:参考**vite-plugin-vue-inspector实现原理,自己实现一个**webpack-plugin-vue-inspector插件
  • 另外一条路:将项目dev环境支持vite 启动开发

我选择的是将项目dev环境支持vite启动开发,原因:vite 目前已经非常成熟,而且借助esbuild极好的开发体验

配置vite

jsx
yarn add vite -D

如果不知道如何开始,可以从vite官网最简单的demo开始。从demo了解下我们需要哪些东西,以及进行哪些配置?

需要的东西

  1. index.html

    html
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite + Vue</title>
      </head>
      <body>
        <div id="app"></div>
        <script type="module" src="/src/main.js"></script>
      </body>
    </html>
    

    此时:入口脚本与html写死了,webpack中都是采用HtmlWebpackPlugin 都是指定入口html然后自动注入入口js,所以这里要调整。可以采用vite-plugin-html-template 解决

  2. vite.config.js

    jsx
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [vue()],
    })
    

    示例demo看不到什么配置,我们看webpack.dev.config 的配置

由于我的项目webpack.dev.conf内容较多,我就只把相关的配置列出来。

jsx
module.exports = merge(baseWebpackConfig, {
	mode: "development",
	...
	devServer: {
		...
		proxy: config.dev.proxyTable,
		...
	},
	module: {
		rules: [
			...
			{
				test: /\.s[ac]ss$/i,
				use: [
					"vue-style-loader",
					...autoInjectSourceMap([
						"css-loader",
						"postcss-loader",
						"sass-loader",
						{
							loader: "sass-resources-loader",
							options: {
								resources: [resolveResouce("variables.scss")],
								sourceMap: config.dev.sourceMap,
							},
						},
					]),
				],
			},
			...
		],
	},
	stats: { children: false },
	plugins: [
		new webpack.DefinePlugin({
			"process.env": config.dev.env,
		}),
		new VueLoaderPlugin(),
		new HtmlWebpackPlugin({
			filename: "index.html",
			template: config.htmlTempletePath,
			inject: true,
		}),
	],
});

通过以上配置,我们需要给vite.config.js 添加对应的配置内容如下

  • 支持环境变量定义
  • 支持sass变量定义
  • 支持alias定义
  • 支持proxyTable

最终vite.config.js 大体内容如下:

jsx
const { defineConfig } = require("vite");
const config = require("./config");
const path = require("path");
const pcwd = process.cwd();
const htmlTemplate = require("vite-plugin-html-template").default;
const vue = require("@vitejs/plugin-vue2");
const envCompatible = require("vite-plugin-env-compatible").default;
const htmlConfig = require('vite-plugin-html-config');
const Inspector = require('vite-plugin-vue-inspector').default;

...

function normalizeAutoInjectConfig(injectConfig) {
	const links = injectConfig.links?.map(item => {
		const res = {};
		for (const key of Object.keys(item)) {
			if (item[key]) {
				res[key] = item[key];
			}
		}
		return res;
	}) ?? [];
	const headScripts = injectConfig.scripts?.map(item => {
		let { importName, globalVariableName, position, ...itemSurplus } = item;
		return itemSurplus;
	}) ?? [];
	return { links, headScripts }
}

module.exports = defineConfig(() => {
	const env = config.dev.env;
	const envObj = {};
	for (const key of Object.keys(env)) {
		envObj[`process.env.${key}`] = env[key];
	}

	return {
		define: envObj,
		mode: "development",
		resolve: {
			alias: {
				"@": path.join(pcwd, "src")
			},
			extensions: [".mjs", ".js", ".mts", ".jsx", ".json", ".vue", ".svg", ".png", ".jpg", ".jpeg"]
		},
		css: {
			devSourcemap: true,
			preprocessorOptions: {
				scss: {
					additionalData: "@import '@/style/variables.scss';",
				}
			}
		},
		server: {
			proxy: config.dev.proxyTable
		},
		plugins: [
			vue(),
			envCompatible({
				moutedPath: "process.env",
			}),
			htmlTemplate({
				entry: "./src/main.js"
			}),
			Inspector({ vue: 2, toggleComboKey: "alt-`" }),
			//! 说明:存在循环依赖解决方法,相关资料:https://github.com/vitejs/vite/issues/3033
			{
				name: "singleHMR",
				handleHotUpdate({ modules }) {
					modules.map((m) => {
						m.importedModules = new Set();
						m.importers = new Set();
					});

					return modules;
				},
			},
		],
	}
})

总结

  • 当我们无从下手时,就可以从一个官网的demo来入手
  • 当从webpack切换至vite时,你想不到会出现哪些问题,就先配出一个最简单的配置,然后逐步完善掉

自从用上vite+https://github.com/webfansplz/vite-plugin-vue-inspector,我再也不用纠结我的代码有没有改对位置了,而且开发体验极速提升。赶快把dev webpack换成vite吧🥰

参考文献

Released under the MIT License.