现在前端有不少打包工具,Farm
RspackMako等等 ,也许未来会出现更多。尽管Vite已经够快了,不过对于新的东西,我是喜欢尝鲜的。Farm对标的是Vite,兼容大部分Vite插件,手上正好有一个简单的大屏项目,花了一个下午迁移到Farm上,老实说,迁移之路并不算平滑,记录一下迁移的历程。
初始工作
使用 Farm 只需要下载 @farmfe/cli @farmfe/core 即可。
pnpm add -D @farmfe/cli @farmfe/core
然后在 vite.config.js 的同级目录下新建 farm.config.mjs,这里需要注意,如果项目没有指定 "type": "module", ,那么必须新建为 farm.config.mjs,farm.config.js 无法正常识别。然后将 vite.config.js 配置迁移到 farm.config.mjs 即可,不需要改动目录结构。
迁移配置项
vite.config.js
import { loadEnv, defineConfig } from "vite";
import { resolve } from "path";
import vue from "@vitejs/plugin-vue";
import { visualizer } from "rollup-plugin-visualizer";
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
import svgLoader from "vite-svg-loader";
// https://vitejs.dev/config/
export default ({ mode }) => {
return defineConfig({
base: "/databoard/",
publicDir: "public",
build: {
outDir: "dist",
assetsDir: "static",
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
},
},
},
resolve: {
alias: {
"@": "/src",
},
},
css: {
preprocessorOptions: {
less: {
modifyVars: {
// 自定义Antdv主题
"primary-color": loadEnv(mode, process.cwd())
.VITE_APP_PRIMARY_COLOR,
"link-color": loadEnv(mode, process.cwd()).VITE_APP_PRIMARY_COLOR,
},
javascriptEnabled: true,
},
scss: {},
},
},
plugins: [
vue(),
svgLoader(),
visualizer(),
Components({
resolvers: [AntDesignVueResolver({ importStyle: "less" })],
}),
],
server: {
host: "0.0.0.0",
port: 8889,
proxy: {
// ...
},
},
});
};
我们逐个迁移
import语句以及export default函数不需要变动,配置项basebuildresolve需要迁移到compilation中
farm.config.mjs
import vue from "@vitejs/plugin-vue";
import { visualizer } from "rollup-plugin-visualizer";
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
import svgLoader from "vite-svg-loader";
import { loadEnv } from "@farmfe/core";
import path from "path";
export default ({ mode }) => {
return {
compilation: {
output: {
// base -> publicPath
publicPath: "/databoard/",
targetEnv: "browser-es2015",
// build.assetsDir -> assets
assetsFilename: "assets/[resourceName].[hash].[ext]",
},
resolve: {
alias: {
"@": path.join(process.cwd(), "src"),
},
},
},
};
};
这里需要注意
resolve.alias,vite.config是支持"@": "/src"相对路径,但是farm.config不支持,需要使用path.join拼接出绝对路径。
Farm虽然兼容Vite插件,但是和Farm自己的插件分别配置在两个配置项中。Farm为Vite插件提供了vitePlugins配置项。
import vue from "@vitejs/plugin-vue";
import { visualizer } from "rollup-plugin-visualizer";
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
import svgLoader from "vite-svg-loader";
import less from "@farmfe/js-plugin-less";
import path from "path";
export default ({ mode }) => {
return {
// Vite 插件
vitePlugins: [
vue(),
svgLoader(),
visualizer(),
Components({
resolvers: [AntDesignVueResolver({ importStyle: "less" })],
}),
],
// Farm 插件
plugins: [],
};
};
css配置,Farm 支持lesssass,但不像 Vite 自带,需要引入 Farm 提供的插件:@farmfe/plugin-sass@farmfe/js-plugin-less。
pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-less
import less from "@farmfe/js-plugin-less";
export default ({ mode }) => {
// loadEnv 返回和 Vite 不同
const VITE_APP_PRIMARY_COLOR = loadEnv(mode, process.cwd())[0]
.VITE_APP_PRIMARY_COLOR;
return {
// Farm 插件
plugins: [
// @farmfe/plugin-sass 可以不用 import 引入
"@farmfe/plugin-sass",
// 将 css.preprocessorOptions 中的 less 配置项迁移到 这里
less({
lessOptions: {
modifyVars: {
// 自定义Antdv主题
"primary-color": VITE_APP_PRIMARY_COLOR,
"link-color": VITE_APP_PRIMARY_COLOR,
},
javascriptEnabled: true,
},
}),
],
};
};
在此处要注意,Farm 的 loadEnv 和 Vite 返回不一样,Vite 返回一个对象, 而 Farm 返回一个数组,需要使用 [0] 取出。
server配置不用改动,但要注意,host不要指定0.0.0.0,否则会丢失hmr功能。
export default ({ mode }) => {
return {
//...
server: {
// host: "0.0.0.0",
port: 8889,
proxy: {
//...
},
},
};
};
配置迁移完成,在 package.json 中添加命令,然后执行 pnpm dev:farm 即可启动项目。
{
"scripts": {
"dev:farm": "farm",
"build:farm": "farm build"
}
}
启动项目
不用想一次性启动成功,不出意外肯定要出意外。执行完命令后,显示报错
没有找到 ../images/shadow1.png 图片,这个代码是一个 css 类中的 background 属性引入的图片找不到。
.circle {
background: url(../images/shadow1.png) no-repeat scroll 100% 100%;
}
排查了下,这块属于粗心留下的无用代码,circle 类已经不再使用,图片也已经被删除。这在 Vite 中不会有影响,但是 Farm 可以排查出无法引入的资源,删除掉无用类后,项目成功启动。
但是打开页面后又出现了报错
这是因为在 store 中使用了 import.meta.glob 快捷绑定模块,Farm 是支持 Vite 的 import.meta.glob 功能的。
const files = import.meta.glob(`./users/*.js`);
Object.keys(files).forEach((key) => {
let name = key.replace(/(\.\/users\/|\.js)/g, "");
users[name] = files[key].default;
});
大屏项目下没有 user 目录,这块代码也属于无用代码。在 Vite 中可以正常运行,找不到会返回空对象。但是 Farm 找不到模块会报错。删除无用代码后,报错消失,但页面还是白屏,控制台有个警告:
找到 router 文件
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
问题就处在 import.meta.env.BASE_URL,BASE_URL 是 Vite 特殊的环境变量,但是 Farm 中并没有,在 env 文件定义一个 VITE_API_BASE_URL 后,问题成功解决。
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_API_BASE_URL),
routes,
});
至此,迁移完成,页面正常打开运行,hmr 功能正常,build 功能正常。
体验
这个项目确实小,不管是冷启动还是热启动,Farm 对比 Vite 都没有太让人惊喜的地方,也许放到大项目一次性请求几十个模块的时候才会有更明显的差距。
但在打包对比上,比 Vite 快了 10s 左右,不知道在大型项目上,差距会不会更明显,此外, Farm 的 build 是默认开启 sourcemap 的,如果不需要,可以在 compilation.sourcemap 中关闭。
总结
虽然迁移踩了一些坑,但好在都能解决,项目可以正常启动。建议可以在一些小项目中使用,dev 启动速度上差距不大,但如果项目配有 CI CD ,build 还是有很可观的提升。