Flutter web - 2 多项目架构设计

简介

因开发需要,需要在一个产库中开发多个前端 H5项目,类似 monorepo ,这样便于项目间的管理和资源复用。

技术选型

melos

melos官网

缺点:使用 melos提供的命令去运行项目时, vscode会失去命令行热更新(运行项目后,后续改动可按r可热更新项目),未在其他 IDE中尝试。且 melos是使用 shell执行命令,作为熟悉 JavaScript的前端同学需增加学习成本。

pnpm

基于以上考虑,最终选择使用 pnpm。虽然 pnpm只是包管理工具,但它允许运行定义在 package.json 文件中的脚本,再通过参数传递即可达到想要的效果。

架构搭建

初始化 package.json

pnpm init

创建运行脚本

在根目录下创建 scripts 文件夹,在文件夹下创建 run.js 脚本。在 package.json 中的 scripts 下新增

"serve": "node scripts/run.js run"

表示执行run.js 脚本中的 run 命令。

修改 package.jsontypemodule

编写运行脚本

项目结构
├─lib
│  ├─project_1
│  │  ├─lib
│  │  │  └─main.dart
│  │  ├─web
│  │  └─pubspec.yaml
│  │     
│  ├─project_2
│  │  ├─lib
│  │  │  └─main.dart
│  │  ├─web
│  │  └─pubspec.yaml
│  │        

flutter run 命令无法指定 web 文件夹目录,所以每个项目都有自己的 web 目录

安装依赖
pnpm i commander -D
使用 commander 检查参数
import { program } from "commander";
program
  .command("run")
  .requiredOption("-p, --project <string>", "project name") // 要运行的项目名
  .requiredOption(      // 运行的环境
    "-e, --env <string>",
    "dev or prod environment",
    (arg) => {
      if (!["dev", "prod"].includes(arg)) {
        throw new Error(
          `Environment must be either 'dev' or 'prod', but got '${arg}'.`
        );
      }
      return arg;
    },
    ["dev", "prod"]
  )
  .option("--web-renderer <string>", "web renderer mode", "html") // 渲染方式
  .action((cmd) => {
    run(cmd);
  });
program.parse(process.argv);

需要传递其他参数的,自行添加

执行对应项目

主要使用 spawn 执行 flutter run 命令,使用 readline 接受命令行输入并传递,解决 melos 缺点。

import path from "path";
import readline from "readline";
import { spawn } from "child_process";

/**
 * @param {{ project: string, env: string, webRenderer: string, host: boolean }} args
 */
function run(args) {
    const runPath = path.resolve(`./lib/${args.project}`);
    // 使用 spawn 执行命令
    const flutterProcess = spawn(
    "flutter.bat",
    [
      "run",
      "-d",
      "chrome",
      `--dart-define=INIT_ENV=${args.env}`, // 设置项目环境
      "--web-renderer",
      args.webRenderer,
    ],
    {
      cwd: runPath, // 设置命令执行路径
    }
  );
  
  // 监听标准输出
  flutterProcess.stdout.on("data", (data) => {
    console.log(data.toString());
  });

  // 监听错误输出
  flutterProcess.stderr.on("data", (data) => {
    console.error(data.toString());
  });
  
  // 接受命令行输入并传递给 flutter run 进程
  const readlineInterface = readline
    .createInterface(process.stdin, process.stdout)
    .on("line", (line) => {
      flutterProcess.stdin.write(line);
  });

  flutterProcess.on("close", () => {
    readlineInterface.close();
  });
}
完整代码
import path from "path";
import readline from "readline";
import { spawn } from "child_process";
import { program } from "commander";

program
  .command("run")
  .requiredOption("-p, --project <string>", "project name") // 要运行的项目名
  .requiredOption(      // 运行的环境
    "-e, --env <string>",
    "dev or prod environment",
    (arg) => {
      if (!["dev", "prod"].includes(arg)) {
        throw new Error(
          `Environment must be either 'dev' or 'prod', but got '${arg}'.`
        );
      }
      return arg;
    },
    ["dev", "prod"]
  )
  .option("--web-renderer <string>", "web renderer mode", "html") // 渲染方式
  .action((cmd) => {
    run(cmd);
  });
program.parse(process.argv);

/**
 * @param {{ project: string, env: string, webRenderer: string, host: boolean }} args
 */
function run(args) {
    const runPath = path.resolve(`./lib/${args.project}`);
    // 使用 spawn 执行命令
    const flutterProcess = spawn(
    "flutter.bat",
    [
      "run",
      "-d",
      "chrome",
      `--dart-define=INIT_ENV=${args.env}`, // 设置项目环境
      "--web-renderer",
      args.webRenderer,
    ],
    {
      cwd: runPath, // 设置命令执行路径
    }
  );
  
  // 监听标准输出
  flutterProcess.stdout.on("data", (data) => {
    console.log(data.toString());
  });

  // 监听错误输出
  flutterProcess.stderr.on("data", (data) => {
    console.error(data.toString());
  });
  
  // 接受命令行输入并传递给 flutter run 进程
  const readlineInterface = readline
    .createInterface(process.stdin, process.stdout)
    .on("line", (line) => {
      flutterProcess.stdin.write(line);
  });

  flutterProcess.on("close", () => {
    readlineInterface.close();
  });
}

以后只要执行

npm run serve -- --project  xxx

即可运行对应项目

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值