构建 VS Code Extension,提高 Flutter 开发效率(一)

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

承接上文系列:

《Flutter 多引擎渲染,在稿定 App 的实践》

《Flutter Web – 让 Web 与 APP UI 一致的另一种可能》

引言

在前文中介绍了 Flutter 多引擎渲染在“稿定 APP” 的实现,以及我们是如何实现将 App Web 化的过程。

在开发过程也好、打包过程也好,中间使用了很多脚本来支撑。

但咱也不是大厂,没必要做自己的 IDE 工具。

那让开发直接去调用脚本,对开发同学来说也不够舒适。

工欲善其事,必先利其器。

VS Code 这记事本[狗头] 提供了强大的插件能力,可以帮我们实现项目开发自动化。

Gaoding Flutter Develop Kit

看官们切勿动手,笔者不是在推广自己插件的哈,这插件就算你们下了也是用不了的,毕竟真实的脚本是跟着项目或者 application-services 走的,这里只是提供一个插件开发思路 ~

介绍

Gaoding Flutter Develop Kit 我们用来做了些什么?

从能力上,大概分为以下三类:

插件聚合

常用插件聚合,减少新入坑选手对 VS Code IDE 的配置成本。

image.png

这一部分其实可以做更进一步,聚合的插件也在 settings.json 上做统一的个性化配置。

执行脚本

  • GaodingFlutter: run generate api 生成 Component API
  • GaodingFlutter: run build web preview & generate docs 构建预览 Web 产物和生成在线文档
  • GaodingFlutter: config application-services project path 配置 application-services 项目路径 (可选)
  • GaodingFlutter: config gd-docs project path 配置 在线文档(gd-docs) 项目路径
  • GaodingFlutter: flutter pub get on workspace 工作空间内项目一键 pub get
  • GaodingFlutter: Attach to Flutter Process Fast 联调 Xcode 更快捷
  • GaodingFlutter: Attach to Flutter on Device Fast 联调 Android Studio 更快捷
  • GaodingFlutterWeb: run generate dart facade & npm run build TS 转 Dart 调用层 & 输出 web 产物

可以看到从 “多引擎组件生成” 这种调起项目脚本到 “快速 attach”、“对所有本地引用的 flutter plugins 项目一键 pub get” 都有。

能简化开发的都可以自定义成我们的独有命令,只需要 command + shift + p,即可调用。

也有部分能力做了可视化按钮:

image.png

比如当前在 ui_components.yaml 文件中,就会多一个按钮,可以执行 GaodingFlutter: run generate api 命令。

自动检查

打开工作空间时,自动检测 Component API 是否有变动,如果有变动则弹框提醒需要执行生成。

减少协作上的沟通成本。

核心原理

抛开细节,里面最重要的就是如何优雅的执行脚本文件了。

笔者这部分也是找了半天的,网上关于如何写 VS Code Extension 的文章更多都是偏基础部分,如何搭项目、如何新增命令这样的。教你如何调用 shell ruby python 脚本的少之又少,特别你还需要执行完脚本的返回值来做界面上的友好提示的时候就更难了。

这里笔者整理了下自己踩过的调用脚本的坑,大概执行脚本有以下2种比较可行:

vscode.Terminal

vscode.Terminal 顾名思义,这个可以新开一个终端进行操作,也是我前面常用的。

优势:可以很直观的在页面上看到执行的脚本到了哪一步,且有关闭时的回调。
劣势:没有可以获取终端输出值的手段,就没办法进行脚本执行异常的情况处理。(笔者在官网找了一圈又一圈,没有任何可用的方式,以前可能有一个,但方法已作废了用不了)

/// 执行终端任务
const excuteTerminalTask = (cmd: string) => {
  terminal = vscode.window.createTerminal({
    name: _TERMINAL_NAME, // 尽量给终端起个名,可以定向关闭终端
  });
  vscode.window.withProgress(
    {
      location: vscode.ProgressLocation.Notification,
      title: 'GaodingFlutter: 正在生成文档 & 构建 Web ...',
      cancellable: true,
    },
    (_, token) => {
      // 取消按钮操作
      token.onCancellationRequested(() => {
        terminal!.dispose();
      });
      terminal!.show(true);
      terminal!.sendText(`${cmd}; exit`); // 执行脚本语句
      return new Promise<void>((resolve) => {
       // 监听关闭
        vscode.window.onDidCloseTerminal((listener) => {
          if (listener === terminal) {
            resolve();
            vscode.window.showInformationMessage('GaodingFlutter: 构建完成');
          }
        });
      });
    }
  );
};

child_process.exec

child_process.exec 可以在子线程中直接执行脚本文件。

优势:可以返回脚本执行结果信息了,特别是报错回调直接捕获。
劣势:子线程执行,具体执行过程看不到。


import * as cp from 'child_process';

// 执行 shell 脚本
function execShell(cmd: string): Promise<String> {
  return new Promise<string>((resolve, reject) => {
    cp.exec(
      cmd,
      {
        encoding: 'utf-8', 
      },
      (err, out) => {
        if (err) {
          return reject(err);
        }
        return resolve(out);
      }
    );
  });
}

这里特别注意的是要加 encoding,不然在执行包含中文的脚本文件就会报错,这里的脚本文件调用其他脚本中存在中文也不行。

比如你调用 shellshell 里面有调用 ruby,就算 shell 里面声明了 utf-8ruby 脚本里有中文都不行,会报错。

后续

这一篇主要讲了如何在 VS Code Extension 中如何调用脚本,说它难其实也不难,但就是找不到一个万全的调用脚本方式,这在查资料上花费了很多时间。

下一篇会详细讲一下整个工程的结构和源码,让想从 0 起步的同学少走弯路。

如果对你开发学习上有丝丝作用,请点个赞[开心] ~

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容