又快又小的 Vite

本文已于本月发过,但由于个人语言不当、考虑欠佳删掉。在此再次向 Volar 作者道歉,本人已与作者取得联系并表达歉意。以后的文章开玩笑定会三思,愿各位谅解。

<本篇已删掉之前的不当言论>

“嘉豪,新的 H5 项目要不用 Vite 整整?” ,听到这番话,被 Webpack 摧残许久的我留下了幸福的眼泪?

需要澄清一点,我们的 H5 项目体量较小,仅能通过短信链接打开。对于这种小的项目来说,实践一些新 姿势 技术是再好不过的,各位不要盲目跟风!

激动.jpeg

Vite

首先 Vite 这个单词咋个读喃?”歪特?v特?维特?“

对于这个问题,官方文档的第一句就给出了答案:Vite (French word for “fast”, pronounced /vit/),法语:快!看到 Vite 这个名字,感觉尤大也想打造自己的 V宇宙

Run 起来?‍♂️

Vite 提供了十分方便的工具来初始化项目:

yarn create @vitejs/app project-name --template vue-ts
 

首先,Vite 只是一个打包工具,就像我们常用的 Webpack/Rollup/Parcel 一样,也就是说 Vite 并不是与 Vue 强相关的,使用 React 也一样。创建好项目之后,就可以执行 yarn serve 命令来运行本地 dev 环境:

{
  "scripts": {
    "dev": "vite", // start dev server
    "build": "vite build", // build for production
    "serve": "vite preview" // locally preview production build
  }
}
 

经常用 Webpack 的开发者应该会清楚,启动本地 dev 环境时需要等八九秒甚至十几秒,但 Vite 很快啊!

WX20210322-230816@2x.png

宫廷玉液酒,一百八一杯。为啥这么快,听我跟你吹… 各位应该都听说过某公司 CTO 不好好工作,沉迷于开源写了一个快的飞起(我愿称其为世界第一快男)的打包工具 —— esbuild。而 Vite 在启动本地开发环境时,便是使用的 esbuild

// vite/dist/node/chunks/dep-1bdbec90.js
// 第 68134 行
async function createServer$2(inlineConfig = {}) {
  // ...
  const server = {
    // ...
    transformWithEsbuild, // 第 68168 行
    // ...
  };
}

// 第26715 行
async function transformWithEsbuild(code, filename, options, inMap) {
  const service = await ensureService();
  try {
    // ...
    const result = await service.transform(code, resolvedOptions); // 第 26735 行
    // ...
  } catch {
    // ...
  }
}

// 第 26702 行
async function ensureService() {
    if (!_servicePromise) {
        _servicePromise = require('esbuild').startService();
    }
    return _servicePromise;
}
 

启动 vite serve 命令时调用顺序便是如此,最终会进入到 esbuildstartService 方法。u1s1,快也就开发者能体会得到,用户并无感知,所以你开发时启动再快,打包后的体积大也没什么卵用。所以,目前来说开发追求的是 “又小又快”

秋名山.jpeg

对于代码压缩的配置,官方文档中有描述道:

- build.minify
	- Type: boolean | 'terser' | 'esbuild'
	- Default: 'terser'
	- Set to false to disable minification, or specify the minifier to use. The default is Terser which is slower 		but produces smaller bundles in most cases. Esbuild minification is significantly faster, but will result in 		 slightly larger bundles.
 

默认使用 terser 进行压缩,但是如果你觉得有点慢,可以设置成 esbuild,弊端就是 esbuild 压缩出来的会大一些。所以更建议使用 terser,毕竟做的产品是给用户做生产环境使用的。但 build 时候使用的却是 rollup

// vite/dist/node/chunks/dep-1bdbec90.js
// 第 46730 行
var build$1 = {
	// ...
	build: build, // 第 46734 行
};

// 第 46446 行
async function build(inlineConfig = {}) {
		// ...
    try {
        return await doBuild(inlineConfig); // 第 46449 行
    }
    finally {
        // ...
    }
}

// 第 46459 行
async function doBuild(inlineConfig = {}) {
  // ...
  const rollup = require('rollup'); // 第 46501 行
  try {
        const bundle = await rollup.rollup({
            // ...
        });
  }
  catch {
    // ...
  }
}
 

上面就是在执行 vite build 时的调用顺序,最后会走到 rollup 进行打包,同时在 doBuild 方法中还对 SSR 打包进行了处理,感兴趣的读者可以自行阅读 Vite 源码(已贴心的标注了具体行数)。

添砖 Java 加瓦?

按照上面的命令创建出来的项目仅支持 VueTS,如果需要支持更多的特性需要我们自行配置,下面会详细讲解。

Router

项目中使用的是 Vue 3 Composition API,故对应使用的是 Vue Router 4+

yarn add vue-router@4
 

使用动态引入的方式实现懒加载:

export const routes = [
  { path: '/', component: () => import('@/pages/home/home.vue') },
	// ...
  // other pages
  {	// 404 page
    path: '/:pathMatch(.*)*',
    component: () => import('@/pages/not-found/not-found.vue'),
  },
];
 

main.ts 中的使用也与 Vue 2+ 稍有不同:

import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { routes } from './routes';
import App from './app.vue';

const app = createApp(App);
const router = createRouter({
  history: createWebHistory(),
  routes,
});

app.use(router);
app.mount('#app');
 

CSS Preprocessors

一般来说,现在的项目都会使用 Less 或 Scss,而不是直接使用 CSS,如果要使用预处理语言,则直接安装对应的预处理语言的依赖即可,就不赘述。而在使用时就与平时使用并无他样:

<style lang="less">
	/* Your less code */
</style>
 

但有时我们可能定义一些全局使用的变量或 mixin,这时候我们经常会使用类似于 less-loaderadditionalData 在每个样式文件头部引入相应的全局文件,从而避免在每个文件中都写 @import "@/styles/mixins.less" 语句,使用 Vite 的操作其实也是一样:

export default defineConfig({
  css: {
    preprocessorOptions: {
      less: {
        additionalData:
          '@import "@/styles/variables";\n@import "@/styles/mixins";\n',
      },
    },
  },
});
 

使用 css.preprocessorOptions.less.additionalData 即可实现,并不需要再安装 某pack 需要安装的各种 loader,简简单单~

WX20210322-230915@2x.png

Alias

其实 ViteWebpack 的配置方法有些相似,但速度却相差甚远(Webpack 骂骂咧咧退出直播间)。比如为了提升开发体验,我们会配置路径简写,将 /src 映射成 @ 之类的:

export default defineConfig({
  resolve: {
    alias: {
      '@': '/src',
      dayjs: 'dayjs/esm',
    },
  },
});
 

Webpack 几乎一模一样,直接在 vite.config.ts 中配置 resolve.alias 字段即可,然后再在 tsconfig.json 中配置:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
	}
}
 

项目中使用到了 dayjs,在上面的例子中,将原本 dayjs 依赖中的 dayjs/index.js 路径手动改到了 dayjs/esm/index.js(ESModule)。

Proxy

至于我们常用的 proxy 和静态资源的访问路径,Vite 也贴心地提供了对应字段来配置:

export default defineConfig({
  base: '静态资源 URL',
  server: {
    proxy: {
      '/api': {
        target: '请求 URL',
        changeOrigin: true,
      },
    },
  },
})
 

无需多言,dddd(懂得都懂)!值得一提的是,之前我们都是通过 process.env.NODE_ENV 来获取环境变量,但在 Vite 中将其挪到了 import.meta.env 中。如要继续使用,则需在 npm script 中添加:

{
  scripts: {
    "start": "NODE_ENV=development vite"
  }
}
 

Assets

项目中添加了很多有很多 svg 图标,当然 svg 可以通过 <img src="icon.svg" /> 来展示,但更多时候我们会在通过 raw-loader 将其转成 string 引入。而在 Vite 中,可以通过在引入路径中添加 ?raw 的方式引入字符串:

import Icon from '@/assets/icon.svg?raw';
 

这样引入的就是 svgXML 字符串,再通过 v-html 展示。Vite 自带 raw-loader 无需额外安装。

Postcss

Vite 也内置了 Postcss 8+,所以只需要在项目根目录添加相应的 postcss.config.js 文件即可。但有些 Postcss 插件使用到还是老版本的 API(比如我们使用的 postcss-px-to-viewport),这就会在 console 中打印一个 warning,但并不妨碍使用。

What’s more

Vite 虽然已经发布到了 2 大版本,但其更新还是很快,有些内容版本还是在频繁的更新,有些修修补补:

vite.png

比如目前 Vite 仅支持兼容到 es2015Vue 3 的测试环境按照其文档配置后还是不 work,后续还需再持续关注下测试的相关配置。

Vue 3 的类型检查一直是个大问题,我们无法通过 tsc 来直接做类型检查,但是我们可以通过尤大钦点的一个 VSCoder 插件 Volar 在开发阶段完成类型检查:

valor.png

开发过程中,该插件会对有类型错误标出下划线,同时也可以运行 verifyAllScripts 检查所有文件的类型。所以我就想:如果我们能够在命令行中直接运行 verifyAllScripts 命令,岂不就可以实现 tsc 的效果了?

volar-vscode.png

现实是残酷的,但作者说相关的工具正在开发中。说来作者也真是效率!我3月2号上午和作者交流时,这个工具还在开发,睡了个午觉就已经发布了!在项目中安装好后,只需运行 vue-tsc 即可实现类型检查!配置在 husky 或者 lint-staged 中,简直香的不要不要的!

tsc.png

End

总的来说,Vite 还是能满足大部分的开发需求,并且开发体验还是不错的。不会像 Webpack/Rollup 等需要些大堆的配置和脚本,基本是开箱即用,相比于我之前常用的 Parcel,快了不止一点。感兴趣的开发者还是可以尝试一下,但如果是用在正式生产项目,还是要慎重考虑一下!毕竟新人要上位还是要经历时间的考验~

(0)
上一篇 2021年3月28日 下午1:29
下一篇 2021年3月28日 下午1:43

相关推荐

发表回复

登录后才能评论