Farm项目这个项目关注很久了,最近几个月Farm 1.0也推出了,对vite的适配也完善了很多,那么直接来尝试一下,我比较喜欢的Vue后台项目是SoybeanAdmin,所以我们就拿他来做个对比吧。
效果对比
项目使用:github.com/soybeanjs/s… 项目的main分支。
先不说别的,先直接看看效果:
vite打包用时15.2s
farm评价用时3.7s左右
vite启动本地服务时间大概2s,但是因为是bundleless,打开页面还要进行一些编译,可能打开页面时间会慢一点
farm的话就得久一点了,但是farm使用的是Partial Bundling的策略,从控制台打印的来看好像就是把很多依赖包都先打包构建好,自然启动时间就长一点了,但是带来的好处就是打开页面之后请求的js数量就少很多了,而且因为已经打包好了,所以请求之后基本可以立刻返回打包好的js,不会出现vite这种可能启动几百ms,但是打开页面等几十个js请求,等好几秒页面才出来的情况。
官方benchmark:
| Startup | HMR (Root) | HMR (Leaf) | Production Build | |
|---|---|---|---|---|
| Webpack | 8035ms | 345ms | 265ms | 11321ms |
| Vite | 3078ms | 35ms | 18ms | 2266ms |
| Rspack | 831ms | 104ms | 96ms | 724ms |
| Farm | 403ms | 11ms | 10ms | 288ms |
不过感觉和Farm官方的benchmark有一点点出入,特别是启动时间,可能如果产物越大差别就没那么明显了。
迁移过程
简单讲一下main分支的代码需要怎么迁移吧:
首先是打包配置定义部分:
// farm.config.ts
import { URL, fileURLToPath } from 'node:url';
import process from 'node:process';
import { defineConfig, loadEnv } from '@farmfe/core';
import { setupVitePlugins } from './build/plugins';
import { createViteProxy, getBuildTime } from './build/config';
import postcss from '@farmfe/js-plugin-postcss'
export default defineConfig(configEnv => {
const viteEnv = loadEnv(configEnv.mode, process.cwd()) as Env.ImportMeta;
const buildTime = getBuildTime();
// @todo: farm/cli包还在重构,下个版本支持获取command和isPreview
// const enableProxy = configEnv.command === 'serve' && !configEnv.isPreview;
const enableProxy = true;
const proxy = createViteProxy(viteEnv, enableProxy);
// uno.config.ts需要用到环境变量,这里先存到 process.env,因为不知道还有没有别的方法
process.env.viteEnv = JSON.stringify(viteEnv);
return {
compilation: {
define: {
BUILD_TIME: JSON.stringify(buildTime)
},
output: {
publicPath: viteEnv.VITE_BASE_URL
},
resolve: {
alias: {
'~': fileURLToPath(new URL('./', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
},
server: {
port: 9527,
open: true,
proxy
},
plugins: [
postcss(),
[
'@farmfe/plugin-sass',
{
additionalData: `@use "@/styles/scss/global.scss" as *;`
}
]
],
vitePlugins: setupVitePlugins(viteEnv, buildTime) as object[]
};
});
./build/plugins 部分代码也需要修改一下:
import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
// import VueDevtools from 'vite-plugin-vue-devtools';
import progress from 'vite-plugin-progress';
import { setupElegantRouter } from './router';
// import { setupUnocss } from './unocss';
import { setupUnplugin } from './unplugin';
import { setupHtmlPlugin } from './html';
export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
const plugins: PluginOption = [
vue({
script: {
defineModel: true
}
}),
vueJsx(),
// VueDevtools(),
setupElegantRouter(),
// setupUnocss(viteEnv),
...setupUnplugin(viteEnv),
progress(),
setupHtmlPlugin(buildTime)
];
return plugins;
}
unocss的vite插件使用到了一些比较特别的vite hook,farm还不支持,所以这里咱们换成postcss插件,安装:@farmfe/js-plugin-postcss 和 @unocss/postcss
创建postcss的配置文件:
// postcss.config.mjs
import UnoCSS from '@unocss/postcss'
export default {
plugins: [
UnoCSS(),
],
}
uno.config.ts文件修改一下:
import path from 'node:path';
import process from 'node:process';
import { defineConfig } from '@unocss/vite';
import transformerDirectives from '@unocss/transformer-directives';
import transformerVariantGroup from '@unocss/transformer-variant-group';
import presetUno from '@unocss/preset-uno';
import type { Theme } from '@unocss/preset-uno';
import { presetSoybeanAdmin } from '@sa/uno-preset';
import presetIcons from '@unocss/preset-icons';
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';
import { themeVars } from './src/theme/vars';
// 上面存的环境变量就在这里使用
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = JSON.parse(process.env.viteEnv as string);
const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon');
const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, '');
export default defineConfig<Theme>({
theme: {
...themeVars,
fontSize: {
'icon-xs': '0.875rem',
'icon-small': '1rem',
icon: '1.125rem',
'icon-large': '1.5rem',
'icon-xl': '2rem'
}
},
shortcuts: {
'card-wrapper': 'rd-8px shadow-sm'
},
transformers: [transformerDirectives(), transformerVariantGroup()],
presets: [
presetUno({ dark: 'class' }),
presetSoybeanAdmin(),
presetIcons({
prefix: `${VITE_ICON_PREFIX}-`,
scale: 1,
extraProperties: {
display: 'inline-block'
},
collections: {
[collectionName]: FileSystemIconLoader(localIconPath, svg =>
svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
)
},
warn: true
})
]
});
最后注释掉src/plugins/assets.ts里的import 'uno.css';
换成在src/styles/css/global.css里使用unocss:
@import './reset.css';
@import './nprogress.css';
@import './transition.css';
@unocss;
html,
body,
#app {
height: 100%;
}
html {
overflow-x: hidden;
}
到此为止,咱们就成功将vite切换到farm了,最后结果可以看这个仓库:github.com/Wyatex/farm…
再额外补个example分支打包时间对比
因为主分支被精简过了,咱们把main分支合并到example分支然后打包试试:
vite打包时间是21s左右
farm的时间就去到6.1s,已经缩短到不到4倍了,看来打包的内容越多打包时间倍数差就没那么大了(手动滑稽),这也可能是这个项目打包时间和benchmark差别大的原因吧。