Rust賦能前端:給我0.02秒,生成一套Vite/Rsbuild前端項(xiàng)目
1. 迎新
相比上一個(gè)版本,我們主要有幾個(gè)新的變化。
新增特性
對(duì)Rsbuild的支持
很早就開(kāi)始關(guān)注到Rsbuild[2]的功能。在不久之前,他們將版本信息更新到1.0。在觀望了幾天之后,發(fā)現(xiàn)Rsbuild在打包和開(kāi)發(fā)階段有著和其他打包工具截然不同的性能優(yōu)勢(shì)。所以,我們團(tuán)隊(duì),也在逐步將Vite替換為Rsbuild。
下面就直接截取它官網(wǎng)的內(nèi)容了。
圖片
圖片
其實(shí)呢,Rsbuild在構(gòu)建項(xiàng)目的時(shí)候,也為我們提供了很多Template。和其他工具一樣(CRA/Vue Cli/Vite)。他們只是為我們提供一個(gè)最基礎(chǔ)的項(xiàng)目。對(duì)于像一些axios/css/狀態(tài)管理都需要自己去配置。
既然,我們團(tuán)隊(duì)也是對(duì)于一些新項(xiàng)目,要用Rsbuild。所以,這次更新cli也將Rsbuild作為一個(gè)打包選項(xiàng)。
體現(xiàn)在Rust代碼中就是下面的邏輯
let _build_tool = match build_tool {
    Some(build_tool) => build_tool,
    None => {
        if default {
            panic!("Fatal: 構(gòu)建工具未指定");
        }
        logger::multiselect_msg("選擇一個(gè)構(gòu)建工具:");
        logger::message("使用上/下箭頭進(jìn)行選擇,使用空格或回車(chē)鍵確認(rèn)。");
        let items = vec!["Vite", "Rsbuild"];
        let selection = Select::with_theme(&ColorfulTheme::default())
            .items(&items)
            .default(0)
            .interact_on_opt(&Term::stderr())?;
        match selection {
            Some(0) => BuildTool::Vite,
            Some(1) => BuildTool::Rsbuild,
            _ => panic!("Fatal: 構(gòu)建工具指定失敗."),
        }
    }
};然后,我們?cè)谑褂媒换ナ綐?gòu)建項(xiàng)目時(shí)候,就可以選擇vite或者rsbuild作為項(xiàng)目的構(gòu)建工具了。
圖片
通過(guò),選擇Rsbuild作為構(gòu)建工具,那么我們就會(huì)生成一個(gè)功能完備的項(xiàng)目。
然后,我們?cè)谥蟮膖emplate-react目錄基礎(chǔ)上加上rusbuild-config的內(nèi)容,在配合一些交互式配置就可以生成一個(gè)rsbuild+react的項(xiàng)目了。
下面是rusbuild-config的內(nèi)容。
├── biome.json
├── index.d.ts
├── index.html
├── package.json
├── rsbuild.config.js
└── src
    └── routers
        └── index.tsx命令自動(dòng)化
在之前的版本中,像一些
- husky的實(shí)例化,
 - 項(xiàng)目初始化后打開(kāi)編輯器
 - 安裝項(xiàng)目依賴
 
這些操作都需要自己手動(dòng)完成。而此次更新之后,這些操作我們都使用了std::process::Command來(lái)自動(dòng)執(zhí)行了。
圖片
體現(xiàn)在Rust代碼中,如下所示(我們拿打開(kāi)Vscode為例子)
use std::process::Command;
use console::style;
use super::logger::{ self, message };
pub fn open_vscode(project_dir: &std::path::PathBuf) {
    logger::command_msg("正在打開(kāi) VS Code...");
    // 使用 `code` 命令打開(kāi)指定的項(xiàng)目目錄
    let status = if cfg!(target_os = "windows") {
        Command::new("cmd").arg("/C").current_dir(project_dir).arg("code").arg(".").status()
    } else {
        Command::new("code").current_dir(project_dir).arg(".").status()
    };
    match status {
        Ok(s) if s.success() => {
            logger::command_success("VS Code 成功打開(kāi)");
        }
        Ok(_) | Err(_) => {
            logger::error("打開(kāi) VS Code 失敗");
            message("確保您已安裝 VS Code,并且 `code` 命令可用");
            message(
                &format!(
                    "{}",
                    style("要將 `code` 命令配置到系統(tǒng) PATH,請(qǐng)按照以下步驟操作:!").underlined()
                )
            );
            message("  1. 打開(kāi) VS Code");
            message("  2. 打開(kāi)命令面板 (按下 `Ctrl + Shift + P`)");
            message("  3. 輸入并選擇 'Shell Command: Install 'code' command in PATH'");
            message("  4. 重啟終端,并再次運(yùn)行此命令");
        }
    }
}其他的操作,如husky的初始化,使用yarn安裝依賴。都是類(lèi)似的操作。
css解決方案和hook,變成可選
在使用cli過(guò)程中,我們發(fā)現(xiàn)有些功能不是很必須的,所以我們讓這些功能變成可選。
圖片
我們是用dialoguer[3]來(lái)實(shí)現(xiàn)這個(gè)的二次確認(rèn)操作。
體現(xiàn)到Rust中就是如下:
let _style = match style {
    Some(style) => style,
    None => {
        if default {
            panic!("Fatal: css解決方案未指定");
        }
        if
            Confirm::with_theme(&ColorfulTheme::default())
                .with_prompt("所構(gòu)建的項(xiàng)目是否需要CSS解決方案(tailwindcss/styled-components)?")
                .interact()
                .unwrap()
        {
            logger::multiselect_msg("選擇一個(gè)css解決方案:");
            logger::message("使用上/下箭頭進(jìn)行選擇,使用空格或回車(chē)鍵確認(rèn)。");
            let items = vec!["tailwindcss", "styled-components"];
            let selection = Select::with_theme(&ColorfulTheme::default())
                .items(&items)
                .default(0)
                .interact_on_opt(&Term::stderr())?;
            match selection {
                Some(0) => Style::TailwindCSS,
                Some(1) => Style::StyledComponents,
                _ => panic!("Fatal: css解決方案指定失敗."),
            }
        } else {
            Style::None
        }
    }
};項(xiàng)目天然支持wasm/web worker(comlink)
我們?cè)谠柬?xiàng)目中,新增了wasm/worker的文件目錄,用于存放項(xiàng)目中可能會(huì)用到的wasm和web worker。
這些功能都是開(kāi)箱即用的。我們已經(jīng)在相應(yīng)的構(gòu)建工具(vite/rsbuild)為大家配置好了。
大家可以在下載完項(xiàng)目后,在home頁(yè)面進(jìn)行驗(yàn)證。(記得把控制臺(tái)打開(kāi))。
下面是vite.worker.config.ts中的相關(guān)配置。
import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await';
import { comlink } from 'vite-plugin-comlink';
const worker = () => {
    return ({
        plugins: () => [wasm(), topLevelAwait(),comlink()],
        })
};
export default worker;我們?cè)谂渲胿ite時(shí),按照功能將其分為幾大類(lèi):
├── vite.plugin.config.ts
├── vite.build.config.ts
├── vite.config.ts
├── vite.define.config.ts
├── vite.server.config.ts
├── vite.worker.config.ts引入code-inspector-plugin
我們?cè)陧?xiàng)目中引入了code-inspector-plugin[4],它是一款點(diǎn)擊頁(yè)面上的 DOM 元素,它能自動(dòng)打開(kāi) IDE 并將光標(biāo)定位至 DOM 的源代碼位置
圖片
通過(guò)tsconfig.json中的配置別名
{
  //...
  "compilerOptions": {
    "baseUrl": ".", // 解析非相對(duì)模塊的基準(zhǔn)目錄
    "paths": { // 設(shè)置路徑映射
      "@/*": ["src/*"],
      "@hooks/*": ["src/hooks/*"],
      "@assets/*": ["src/assets/*"],
      "@utils/*": ["src/utils/*"],
      "@components/*": ["src/components/*"],
      "@pages/*": ["src/pages/*"],
      "@api/*": ["src/api/*"],
      "@network/*": ["src/services/*"]
    }
  },
  //....
}設(shè)置vscode的規(guī)范
我們?cè)跇?gòu)建項(xiàng)目的時(shí)候,會(huì)自動(dòng)生成.vscode的文件。
其中有幾點(diǎn)比較好玩:
- 設(shè)置explorer.fileNesting.patterns配置文件分組
 
{
"explorer.fileNesting.patterns": {
    "tsconfig.json": "tsconfig.*.json, env.d.ts",
    "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .prettier*, prettier*, .editorconfig",
    ".env":".env.*",
    "vite.config.ts":"vite.*.config.ts"
  },
}
圖片
- 設(shè)置search.exclude限定搜索范圍。
 
{
  "search.exclude": {
    "**/node_modules": true,
    "**/*.log": true,
    "**/*.log*": true,
    //省略部分代碼
  },
}相關(guān)的配置還有files.exclude。
- 設(shè)置cSpell.words規(guī)范拼寫(xiě)檢查。
 
{
  "cSpell.words": [
    "vben",
    "windi",
    "browserslist",
    "tailwindcss",
    "esnext",
    "antv",
    //省略部分代碼
  ]
}2. 辭舊
之前呢,我們?cè)趖emplate-react中冗余了很多工具方法或者特性。
例如Sentry/Logging。
而此次的更新,我們將前端項(xiàng)目的結(jié)構(gòu)做了精簡(jiǎn)。
我們只保留了一個(gè)能夠直接啟動(dòng)的目錄結(jié)構(gòu),其他冗余的功能,現(xiàn)在剔除掉了。因?yàn)橛行┬枨髮?duì)于一個(gè)項(xiàng)目來(lái)講不是必須品。
├── src
│   ├── App.tsx
│   ├── api
│   │   ├── config.ts
│   │   └── test.ts
│   ├── components
│   │   ├── ErrorPage
│   │   │   └── index.tsx
│   │   └── Loading
│   │       └── index.tsx
│   ├── constants
│   │   └── pages.ts
│   ├── contexts
│   │   └── global.ts
│   ├── index.css
│   ├── main.tsx
│   ├── pages
│   │   ├── Home
│   │   │   └── index.tsx
│   │   └── Login
│   │       └── index.tsx
│   ├── routers
│   │   └── index.tsx
│   ├── services
│   │   ├── ApiError.ts
│   │   └── HTTPService.ts
│   ├── style
│   │   └── global.css
│   ├── types
│   │   └── index.ts
│   ├── utils
│   │   ├── deviceDetection
│   │   │   └── index.ts
│   │   ├── envDetection
│   │   │   └── index.ts
│   │   ├── index.ts
│   │   └── storage
│   │       └── localStorage
│   │           ├── helpers.ts
│   │           └── index.ts
│   ├── wasm
│   │   └── fibonacci
│   │       ├── fibonacci_wasm.d.ts
│   │       ├── fibonacci_wasm_bg.wasm
│   │       ├── fibonacci_wasm_bg.wasm.d.ts
│   │       └── index.js
│   └── worker
│       └── fibonacciWorker.ts
├── tsconfig.json
└── yarn.lock3. 展望
其實(shí)呢,這個(gè)項(xiàng)目還有很多功能需要完善。
如果大家使用了會(huì)發(fā)現(xiàn),我們有些的工具是限定死的。
例如,我們推崇只使用yarn來(lái)作為包管理器。使用vscode作為IDE。
這塊也是我們后期需要豐富的地方。
這里我們有一個(gè)TODO List
- 兼容pnpm/npm/yarn
 - 兼容常規(guī)IDE
 - 兼容更多構(gòu)建工具Webpack/Vite/Rsbuild
 - 兼容Vue的項(xiàng)目構(gòu)建。
 - 兼容monorepo項(xiàng)目的構(gòu)建
 
針對(duì)第四/五點(diǎn),其實(shí)我們已經(jīng)在做這方面的努力了。
圖片
對(duì)應(yīng)的我們已經(jīng)構(gòu)建好對(duì)于的枚舉類(lèi)型- FrameworksType
#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
pub enum FrameworksType {
    React,
    Vue,
}同時(shí),在create_project函數(shù)中,已經(jīng)有了對(duì)Monorepo和FrameworksType的渴望。只不過(guò),因?yàn)橛行┬Ч€沒(méi)達(dá)到要求。這方面的需求先擱置了。我們打算把這些需求放到下一個(gè)大版本中。
圖片
Reference
[1]f_cli_f: https://www.npmjs.com/package/f_cli_f
[2]Rsbuild: https://rsbuild.dev/zh/guide/start/
[3]dialoguer: https://github.com/console-rs/dialoguer
[4]code-inspector-plugin: https://inspector.fe-dev.cn/















 
 
 

















 
 
 
 