airbnb/goji-js

[Proposal] New bridge file template engine by React SSR

malash opened this issue · 1 comments

Why

Bridge files in Goji means the static wxml/wxss/json files generated by Webpack in dist/_goji folder. Now Goji 0.6 use EJS as template engien to generator these files.

But there are some cons of EJS:

  1. No type checking. EJS doesn't support TypeScript.
  2. Hard to abstruct and reuse same templates.
  3. No test case and coverage.

What

I propose to use React and SSR as template engine to generate bridge files.

For example, if you'd like to generate <view wx:if="{{type === 'view'}}"></view> you can use

const BridgeA = () => {
  const type = 'view';
  return <View wxIf={`{{type === '${type}'}}`}></View>
}
console.log(ReactDOMServer.renderToStaticMarkup(<BridgeA />);

How

Here is a full example how to implement this proposal:

import * as React from "react";
import ReactDOMServer from "react-dom/server";

interface CommonBridgeProps {
  className?: string;
  wxIf?: string;
  wxElse?: string;
  wxElif?: string;
  wxFor?: string;
  wxKey?: string;
  wxForItem?: string;
  wxForIndex?: string;
}

function factoryBridgeComponent<Props>(type: string) {
  const comp = (props: React.PropsWithChildren<Props & CommonBridgeProps>) => {
    const {
      wxFor,
      wxIf,
      wxKey,
      wxElse,
      wxElif,
      wxForItem,
      wxForIndex,
      ...restProps
    } = props;
    return React.createElement("" + type, {
      "wx:if": wxIf,
      "wx:else": wxElse,
      "wx:elif": wxElif,
      "wx:for": wxFor,
      "wx:key": wxKey,
      "wx:for-item": wxForItem,
      "wx:for-index": wxForIndex,
      ...restProps
    });
  };
  return comp;
}

const View = factoryBridgeComponent<{ id?: string }>("view");

export default function App() {
  return (
    <View wxFor="xx" wxForItem="bb">
      hi
    </View>
  );
}

const html = ReactDOMServer.renderToStaticMarkup(<App />);
console.log(html);

This proposal solved these probleams:

  1. No type checking. EJS doesn't support TypeScript.
    React and ReactDOM support TypeScript.
  2. Hard to abstruct and reuse same templates.
    We can use React components to regroup bridge templates.
const BridgeA = () => {
  const type = 'view';
  return <View wxIf={`{{type === '${type}'}}`}></View>
}
const BridgeB = () => {
  return <View><BridgeA /><View>;
}
console.log(ReactDOMServer.renderToStaticMarkup(<BridgeB />));
// <view><view wx:if="{{type === 'view'}}"></view></view>
  1. No test case and coverage.
    We can use Jest to write test cases and compute test coverage.

Finally we chosen template string to refactor the bridge files.

PRs:
#95
#96
#98