泛微Ecology 9代码块开发框架:编译JSX和SCSS

编译JSX

问题

OA系统前端使用React开发,我们的业务代码中也会写React组件。React组件通常用JSX语法编写(形如<Component/>),然后编译成原生JS语法(形如React.createElement(Component, ...))。我们的开发框架目前对JS代码只是简单地组装,浏览器运行的就是我们直接写出来的代码,因此在JS源文件中只能写原生JS语法,这对编写React组件很不方便。因此,开发框架需要支持JSX语法的编译。

技术选型

使用Babel实现将JSX语法编译为原生JS语法。

兼容性

JSX语法是原生JS语法的超集,IDE支持在.js扩展名的源文件中使用JSX语法,因此,我们直接将已有的index.js统一看作JSX语法,统一将其编译为原生JS语法。

实现

安装依赖@babel/core、@babel/preset-react。

修改构建程序:

const babel = require("@babel/core");

/** 编译JSX语法为原生JS语法 */
function compileJSX(code) {
    const OPTIONS = {
        presets: ["@babel/preset-react"],
    };
    return babel.transformSync(code, OPTIONS).code;
}

/** 获取JS代码 */
function getJS(scriptDirPath) {
    const jsxFilePath = path.resolve(scriptDirPath, "index.js");
    const jsx = fs.readFileSync(jsxFilePath, {encoding: "UTF-8"});
    return compileJSX(jsx);
}

// 构建时
const js = getJS(scriptDirPath);

编译SCSS

问题

用原生CSS语法写复杂样式时很麻烦,因此我们希望通过CSS预处理器(CSS preprocesssor)来降低复杂性。

技术选型

使用Sass的SCSS语法,它是原生CSS语法的超集,增加了嵌套、变量、单行注释等方便的特性,易学易用易读。

使用sass库将SCSS语法编译为原生CSS语法。

兼容性

之前已经写了不少index.css,但这里不能像JS那样,直接将.css的内容看作SCSS语法,因为IDE不支持,会报错。

我们有两种解决办法:

  1. 将所有index.css全部改名为index.scss,然后开发框架只支持index.scss,并要求团队以后必须使用index.scss这个名称,这样更简单。
  2. 同时支持index.css(原生CSS语法)和index.scss(SCSS语法),并规定index.scss优先于index.css,这样两种名称都可以用。

考虑到团队的实际情况,考虑到所有人都熟悉CSS但并非所有人都熟悉SCSS,考虑到SCSS只在少数复杂场景下使用才有必要,那么,应该保留对index.css的支持。

实现

安装依赖sass。

修改构建程序:

const sass = require("sass");

/** 编译SCSS语法为原生CSS语法 */
function compileSCSS(code) {
    return sass.compileString(code).css;
}

/** 获取CSS代码 */
function getCSS(scriptDirPath) {
    const scssFilePath = path.resolve(scriptDirPath, "index.scss");
    const cssFilePath = path.resolve(scriptDirPath, "index.css");
    if (fs.existsSync(scssFilePath)) {
        const scss = fs.readFileSync(scssFilePath, {encoding: "UTF-8"});
        return compileSCSS(scss);
    } else if (fs.existsSync(cssFilePath)) {
        return fs.readFileSync(cssFilePath, {encoding: "UTF-8"});
    } else {
        return "";
    }
}

// 构建时
const css = getCSS(scriptDirPath);

异常处理

之前的构建只是简单地读取、组装,所以一直没有遇到构建失败的情况。但在支持JSX和SCSS的编译后,构建就不一定能成功了,比如SCSS代码中有语法错误,编译时就会抛异常,导致整个构建程序退出。

因此,要在构建脚本目录时做异常处理,在控制台中报告构建失败,并打印异常。