Farm:Rust构建的下一代前端构建器
   笔记    0 comment
Farm:Rust构建的下一代前端构建器
   笔记    0 comment

一、Farm及其优势

1. 什么是Farm

Farm 是一个非常快的基于 Rust 的 Web 构建工具,用于构建web和nodejs应用。Fram提供快速的编译和hmr,为大型前端项目提供更加极致的编译效率。

2. Farm与传统构建器的区别

2.1 vite/snowpack

此类工具主要有下面三个特性:

依然存在的弊端:

2.2 Farm

Farm的设计理念:

二、Farm的基础配置

1. 配置文件规范

默认情况下,Farm 从项目根目录下的“farm.config.ts|js|mjs”文件中读取配置。

import { defineConfig } from "@farmfe/core";

export default defineConfig({
  root: process.cwd(), // // 编译的根目录
  // 编译选项
  compilation: {
    //...
  },
  // 开发服务器选项
  server: {
    hmr: true,
    //...
  },
  // 插件配置
  plugins: [],
});

2. 编译(complilation)配置

所有与编译相关的配置都在 compilation 配置对象中,这里介绍一些常用的配置,弯针配置参考官方文档 Farm | 编译配置

配置文件示例

// ...
export default defineConfig({
  compilation: {
      //...
  }
  // ...
});
2. 1 Input、output

Input项目的入口点。 Input 的文件可以是html、ts/js/tsx/jsx、css 或通过插件支持的其他文件。

import { defineConfig } from "@farmfe/core";

export default defineConfig({
  compilation: {
    input: {
      index: "./index.html",
      //对于多页面程序,可配置多个页面的入口文件  
      //about: "./about.html",
    },
  },
  // ..
})

Ouput项目的输出目录。ouput的interface 定义如下:

interface OutputOptions {
  // 局部打包后,入口文件所在资源的文件名配置
  entryFilename?: string;
  // 局部打包后,除入口资源外的其他资源输入文件名配置
  filename?: string;
  // 输入目录,默认'dist'
  path?: string;
  // public path:资源加载前缀
  publicPath?: string;//publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
  // 静态资源文件名配置
  assetsFilename?: string;
  // 目标执行环境,浏览器或者 Node
  targetEnv?: "browser" | "node";
  // 输出模块格式
  format?: "cjs" | "esm";
}
ouput.targetEnv

默认值: "browser-es2017"

Farm 会自动为您指定的 targetEnv 注入 polyfill 和降级语法(对于脚本和 css),支持的 targetEnv 如下:

browser:

  • browser-es2017:将项目编译到原生支持 async wait 的浏览器。
  • browser-es2015:将项目编译到原生支持 es6 features 的浏览器。
  • browser-legacy:将项目编译为ES5,例如IE9。 请注意,这可能会引入大量的填充,从而使生产规模更大。 确保您确实需要支持 IE9 等旧版浏览器。
  • browser-esnext:将项目编译到最新的现代浏览器,不会注入任何polyfill。
  • browserbrowser-es2017的别名

nodejs:

  • node16:将项目编译到Node 16
  • node-legacy:将项目编译到 Node 10
  • node-next:将项目编译到最新的 Node 版本,不会注入任何 polyfill。
  • nodenode16的别名
2.2 resolve

配置解析依赖相关的选项,interface定义如下:

interface ResolveOptions {
  extensions?: string[];
  alias?: Record<string, string>;
  mainFields?: string[];
  conditions?: string[];
  symlinks?: boolean;
  strictExports?: boolean;
}
resolve.extensions

配置解析依赖时的后缀,默认值:["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"],当解析一个文件时,如./index,未找到时,会按照配置顺序依次匹配,直到找到。

resolve.alias
export default defineConfig({
compilation: {
 resolve: {
   alias: {
     "/@": path.join(process.cwd(), "src"),
     stream$: "readable-stream",
      "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
   },
 },
},
});

配置解析路径别名。默认值:{}。如/@/pages 将会被替换为,/root/src/pages

2.3 define

全局变量注入,配置的变量名和值将会在编译时注入到产物中。Farm 默认注入 process.env.NODE_ENV 以及部分 Farm 自身使用的变量比如 FARM_HMR_PORT

export default defineConfig({
  compilation: {
    define: {
      MY_VAR: 123,
    },
  },
});
2.4 mode

默认值: 对于 start、watch 命令是 development,对于 build 命令是 production

配置编译模式,为了优化开发时性能,在没有手动配置生产优化相关选项(minify,tree shake 等)时,默认在 development 下会禁用生产环境优化比如压缩和 tree shake,在 production 模式下启用。

2.6 assets

配置额外视为静态资源的文件后缀,通过assets.include配置。如下面把markdown文件视为静态文件。

export default defineConfig({
  compilation: {
    assets: {
      include: ["md"],
    },
  },
});
2.7 css、script
css

module.path:

​ 默认值:["\\.module\\.(css|scss|sass|less)"]

​ 配置哪些路径对应的模块会被视为 CSS 模块。配置使用正则字符串。默认是以 .module.(css|scss|sass|less) 结尾的文件。

module.indentName:

​ 配置生成的 CSS Modules 类名,默认是 [name]-[hash][name], [hash] 为占位符(也是目前支持的所有占位符)。[name] 表示原始类名,[hash] 表示该css 文件 id 的 hash。

script

target:配置 Farm 解析 js/jsx/ts/tsx 的 AST 以及生成代码时支持的 ES 语法版本。 可选值:es5, es6, es2015 - es2023, esnext

2.8 partialBundling

配置 Farm 局部打包的行为。

export interface FarmPartialBundlingConfig {
  targetConcurrentRequests?: number;  
  targetMinSize?: number;
  targetMaxSize?: number;
  groups?: {
    name: string;
    test: string[];
    groupType?: "mutable" | "immutable";
    resourceType?: "all" | "initial" | "async";
  }[];
  enforceResources?: {
    name: string;
    test: string[];
  }[];
  enforceTargetConcurrentRequests?: boolean;
  enforceTargetMinSize?: boolean;
  immutableModules?: string[];
}
targetConcurrentRequests

默认值:25。Farm 尝试生成尽可能接近此配置值的资源数量,控制初始资源加载或动态资源加载的并发请求数量。

targetMaxSize、targetMinSize

默认值:targetMinSize:20 * 1024 bytes, 20 KB、targetMaxSize:1500 * 1024 bytes, 1500 KB分别代表minify 和 gzip 之前生成的资源的最大和最小体积。targetMinSize 并不一定保证满足,可以配置enforceTargetMinSize可用于强制限制最小的大小。

2.9 lazyCompilation、treeShaking、minify
lazyCompilation

默认值: 在开发模式是 true,构建模式是 false是否启用懒编译,配置为 false 关闭。参考 懒编译

treeShaking

默认值: 在开发模式是 false,构建模式是 true是否启用 tree shake,配置为 false 关闭。参考 Tree Shake

minify

默认值: 在开发模式是 false,构建模式是 true

类型: bool | JsMinifyOptions是否启用压缩,开启后将会对产物进行压缩和混淆。参考 压缩

minify.include

默认:[],类型string[]包含需要压缩的模块,默认全部,仅在 minify.modeminify-module 生效

minify.exclude

默认:["*.min.(js|css|html)"],类型string[]排除不需要压缩模块,仅在 minify.modeminify-module 生效

minify.mode

默认值: 'minify-module',类型'minify-module' | 'minify-resource-pot'minify-module 模块级别 minify,可以通过参数控制需要 minify 哪些模块,压缩的更为精细,效率更好。minify-resource-pot· ResourcePot 级别 minify,无法通过参数控制具体的模块

2.10 presetEnv

配置对哪些模块注入语法降级。默认在开发环境为false,构建模式为true。presetEnv的接口定义如下:

type FarmPresetEnvConfig =
  | boolean
  | {
      include?: string[];
      exclude?: string[];
      // TODO using swc's config
      options?: any;
      assumptions?: any;
    };
include

默认值:[] 配置额外包含哪些模块进行语法降级。

exclude

默认值:['node_modules/']。默认不对node_modules目录进行polyfill,如果需要请使用include添加。

option

默认值:降级到es5,详细参考

2.11 comments

配置如何处理注释,默认值license:

3. 开发服务器(devServer)配置

配置Farm 的运行相关配置项,所有的配置都在server中进行配置。如下是一个配置示例:

import type { UserConfig } from "@farmfe/core";

function defineConfig(config: UserConfig) {
  return config;
}

export default defineConfig({
  server: {
    port: 9000,
    // ...
  },
});
3.1 port

dev server的运行监听端口,默认值:9000

3.2 hmr

默认对于 farm start命令开启,其他命令关闭。

启用 HMR,将会监听编译过程中涉及到的模块的变动,当模块变化时,自动触发重编译并将结果推送给 Farm Runtime 进行更新。端口和主机等配置可在hmr中进行配置,比如:

import type { UserConfig } from "@farmfe/core";

function defineConfig(config: UserConfig) {
  return config;
}

export default defineConfig({
  server: {
    hmr:{
        port:9801,//默认值
        host:"localhost"//默认值
    }
    // ...
  },
});
3.3 proxy

配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

import type { UserConfig } from "@farmfe/core";

function defineConfig(config: UserConfig) {
  return config;
}

export default defineConfig({
  server: {
    proxy: {
        '/api':{
            target:"https://xxzxka.eu.org/app",
            changeOrigin:true,
            pathRewrite: (path: any) => path.replace(/^\/api/, ""),
        }
    },
  },
});
3.4 open

配置完成编译运行后是否自动打开浏览器到对应的页面。默认值:false

3.5 plugins

配置 Farm 的 Dev Server 插件,通过 Dev Server 插件可以扩展 DevServer 的上下文,添加 middleware 等。

export function hmrPlugin(devServer: DevServer) {
  const { config, logger } = devServer;
  if (config.hmr) {
    devServer.ws = new WebSocketServer({
      port: config.hmr.port,
      host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
      devServer.getCompiler(),
      devServer,
      logger
    );
  }
}

4. 通用配置

4.1 目录(dir)配置
envdir、envPrefix

配置目录以加载 .env.env.development.env.Production 文件。 默认情况下它与 root 相同。

import { defineConfig } from '@farmfe/core';
import { resolve } from 'path';
export default defineConfig({
  envPrefix: ['FARM_', 'CUSTOM_PREFIX_', 'NEW_'],
  envDir: resolve(process.cwd(), './env'),
});
publicDir

默认:public

publicDir 下的文件将始终被视为静态资源。 在 dev 时可以通过 dev server 直接访问,在构建时会将其复制到 output.path

比如将字体等静态资源添加到 public 目录,并将它们用作 /xxx.ttf

4.2 插件(Plugins)配置
Rust插件

Rust插件使用package name配置使用,默认值[],在字段plugins中声明配置要使用的插件。当需要配置插件项时,使用[packageName,optionsObject]格式。具体如下:

export default defineConfig({
  // ...
  plugins: [
    //基本语法配置  
    "@farmfe/plugin-sass"  
    // 使用数组语法来配置 Rust 插件
    [
      // Rust 插件的名称
      "@farmfe/plugin-sass",
      // Rust 插件的选项
      {
        additionalData: '@use "@/global-variables.scss";'
      }
    ],
  ],
});
Js插件

Js插件本质就是一个函数对象。默认值{},在字段plugins中声明配置要使用的插件。

import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

export default defineConfig({
  plugins: [
    farmPostcssPlugin({
      // ... 配置 postcss 选项
    })
  ],
});

可以通过priority配置插件的优先级,插件本身返回一个配置对象,可以结合对象的展开和priority组合,如farmPostcssPlugin:

import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

export default defineConfig({
  plugins: [
    {
        ...farmPostcssPlugin(
            {
                //插件的配置项目
            }
        ),
        //内部插件的优先级都是100,如果想让插件先执行,就设置大于100,否则设置小于100。
        priority:100   
    }
  ],
});

提示

Js插件必须要实现filter,因为Js的速度相较于Rust很慢,通过filter过滤掉不需要处理的类型,可以提高运行速度。

Vite/Rollup/Unplugin插件

(1) 使用vite插件

Farm 兼容 Vite 插件,默认值[],在字段vitePlugins中声明配置要使用的插件。首先安装vite插件:

npm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D

然后在farm.config.ts中的vitePlugins直接配置:

import vue from '@vitejs/plugin-vue',
import vueJsx from '@vitejs/plugin-vue-jsx';

export default defineConfig({
  // 配置vite插件
  vitePlugins: [
    vue(),
    vueJsx()
  ]
});

为了提高 vite 插件的性能,您可以使用返回过滤器函数语法

import vue from '@vitejs/plugin-vue',

// // 使用Farm 中 Vite 插件的函数语法
function configureVitePluginVue() {
  // 返回插件及其过滤器
  return {
    // 使用 vue 插件
    vitePlugin: vue(),
    // 为其配置过滤器。 不匹配的模块路径将被跳过。
    filters: ['\\.vue$', '\\\\0.+']
  };
}

export default defineConfig({
  vitePlugins: [
    configureVitePluginVue
  ]
});

(2)使用unplugin插件

在Farm中使用unplugin插件,在字段vitePlugins中声明配置要使用的插件。,可以实现引入第三方组件库以及AutoImport等功能。

安装:

npm add unplugin-auto-import unplugin-vue-components -D

使用:

import vue from '@vitejs/plugin-vue',
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  vitePlugins: [
    vue(),
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
      resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
  ]
});
Responses