Skip to content

Commit

Permalink
fix: vuejs build (#200)
Browse files Browse the repository at this point in the history
- fix compiler
- added compiler and vue-codemod package
- storybook
- fix mitosis errors while build
- added events interopability with vue
  • Loading branch information
yyyyaaa authored Sep 15, 2024
1 parent 3e19dcc commit 29cd673
Show file tree
Hide file tree
Showing 115 changed files with 23,281 additions and 26,299 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ jobs:
run: pnpm install

- name: Build and lint
run: pnpm mitosis:react && pnpm b:react
run: pnpm c:react
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ packages/vue/src
.parcel-cache
parcel-bundle-reports
/src/**/dist

*storybook.log
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ The Design System for the Interchain
- [Compiler](#compiler)
- [Icons](#icons)
- [Customizing theme](#customizing-theme)
- [Package dev scripts in root package.json](#package-dev-scripts-in-root-packagejson)
- [Convention](#convention)
- [Related](#related)
- [Credits](#credits)

Expand Down Expand Up @@ -79,6 +81,42 @@ Check [Icon guide](./docs/icons.md) to know how to add more icons

Check [Customizing guide](./docs/custom-theme.md) to know how to customize the default theme.

## Package dev scripts in root package.json
- `t:<target>` to compile target framework (t is short for transpile)
- `b:<target>` to bundle target framework
- `c:<target>` to compile and bundle target framework, it's equivalent to sequentially running `pnpm run t:<target> && pnpm run b:<target>`

## Convention

- Component file names must end with `*.lite.tsx`
- Style sheets must be in `*.css.ts` files, this is because we use a styling solution called `vanilla-extract` to have a CSS-in-JS API across all frameworks.
- For a component, you must use default export, not named export. This is a limitation of Mitosis
- There are more rules and limitations, please read more about Mitosis [here](https://github.com/BuilderIO/mitosis/tree/main/docs)
- To quickly test to see the compilation result from one Mitosis to any framework source code, please use
[mitosis sandbox](https://mitosis.builder.io/). It's similar to TS playground but for Mitosis testing purpose.
- [Vue specifics] Event handlers
- Event handlers in `<template>` must be prefixed with `on`
- Event handlers must be defined in `useStore` hook with a getter function `get eventHandlers()` with exact name. A template for this is as below:

```ts
get eventHandlers() {
const handlers: Record<string, (event: any) => void> = {};
const eventProps = [
"onClick",
"onDoubleClick",
// Add other event names here
]
eventProps.forEach((eventName) => {
if (props[eventName]) {
handlers[eventName] = (event: any) => props[eventName](event);
}
});

return handlers;
}
```
- You can then attach the event handlers to the JSX tag with spread attribute `{...state.eventHandlers}`, this will be transformed to be a `v-on` directive in Vue

## Related

Checkout these related projects:
Expand Down
2 changes: 1 addition & 1 deletion apps/vue-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"rainbow-sprinkles": "^0.17.1",
"tailwindcss": "^3.3.5",
"typescript": "^5.4.2",
"vite": "^5.3.1",
"vite": "^5.4.2",
"vite-plugin-checker": "^0.6.4",
"vue-tsc": "^1.8.22",
"zustand": "^4.5.2"
Expand Down
75 changes: 66 additions & 9 deletions compiler/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ const optionDefinitions = [
{ name: "dev", type: Boolean },
];

function applyFixReactTypeIssues(content, filePath, target) {
if (target === "react" && !filePath.endsWith(".lite.tsx")) {
return fixReactTypeIssues(content);
}
return content;
}

function stripVueJsxExtension(filePath) {
// .lite.tsx file is processed by Mitosis compiler
if (filePath.endsWith(".lite.tsx")) {
return filePath;
}

return filePath.endsWith(".tsx")
? filePath.replace(/\.tsx$/, ".ts")
: filePath;
}

async function compile(rawOptions) {
const { watcherEvents, ...defaultOptions } = rawOptions;

Expand Down Expand Up @@ -80,7 +98,34 @@ async function compile(rawOptions) {
}

// Move src to all the package folder
fs.copySync("src", `${outPath}/src`);
// fs.copySync("src", `${outPath}/src`);

// Move src to all the package folder
const srcFiles = glob.sync("src/**/*");
const allowList = compileAllowList[options.target];
const doesTargetHaveAllowList = allowList != null;

srcFiles.forEach((file) => {
const relativePath = path.relative("src", file);
let destPath = path.join(outPath, "src", relativePath);

if (doesTargetHaveAllowList && !file.startsWith("src/ui/shared")) {
const isAllowed = allowList.some(
(allowed) =>
file.includes(`src/ui/${allowed}/`) || !file.startsWith("src/ui/"),
);
if (!isAllowed) return;
}

if (fs.lstatSync(file).isDirectory()) {
fs.ensureDirSync(destPath);
} else {
if (options.target === "vue") {
destPath = stripVueJsxExtension(destPath);
}
fs.copySync(file, destPath);
}
});

// For Vue, we need to add .vue to the export statement
if (options.target === "vue") {
Expand Down Expand Up @@ -110,6 +155,8 @@ async function compile(rawOptions) {
data.replace(/\~\//g, "../../"),
);

result = applyFixReactTypeIssues(result, element, options.target);

fs.writeFileSync(element, result, "utf8");
});

Expand All @@ -118,8 +165,6 @@ async function compile(rawOptions) {
// Export only the elements we want with matching filters:
// - CLI flag --elements
// - allowList
const doesTargetHaveAllowList = compileAllowList[options.target] != null;

if (cliConfig.elements || doesTargetHaveAllowList) {
const filterWithAllowList = (elements) => {
const elementsToFilter = doesTargetHaveAllowList
Expand Down Expand Up @@ -194,19 +239,31 @@ async function compile(rawOptions) {
parsedPath.ext === ".tsx" && parsedPath.name.includes(".lite");
const isScaffold = parsedPath.dir.includes("scaffolds");

const targetPath = path.join(
let targetPath = path.join(
outPath,
parsedPath.dir.slice(parsedPath.dir.indexOf("src")),
parsedPath.base,
);

if (options.target === "vue") {
targetPath = stripVueJsxExtension(targetPath);
}

if (event.type === "create" || event.type === "update") {
// Only process non lite jsx files in this handler
if (isLiteJSXComponent || isScaffold) return;

try {
const fileContent = await fsPromise.readFile(event.path, "utf-8");
await fsPromise.writeFile(targetPath, removeLiteExtension(fileContent));
let fileContent = await fsPromise.readFile(event.path, "utf-8");
fileContent = removeLiteExtension(fileContent);

fileContent = applyFixReactTypeIssues(
fileContent,
event.path,
options.target,
);

await fsPromise.writeFile(targetPath, fileContent);
} catch (err) {
console.log(`handleWatcherEvents() [${event.type}] event error `, err);
}
Expand All @@ -223,7 +280,7 @@ async function compile(rawOptions) {

async function compileMitosisComponent(filepath) {
const file = path.parse(filepath);
const outFile = `${outPath}/${file.dir}/${file.name.replace(".lite", "")}.${
let outFile = `${outPath}/${file.dir}/${file.name.replace(".lite", "")}.${
options.extension
}`;

Expand All @@ -240,13 +297,13 @@ async function compile(rawOptions) {
api: options.api,
state: options.state,
styles: options.styles,
config: "./compiler/mitosis.config.js",
config: path.resolve(__dirname, "./mitosis.config.js"),
},
array: [filepath],
},
strings: stringTools.strings,
filesystem: filesystemTools.filesystem,
print: { ...printTools.print, info: () => null },
print: { ...printTools.print },
});

return {
Expand Down
36 changes: 17 additions & 19 deletions compiler/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,23 @@ class Cache {
}

async build(filePaths = []) {
const promises = [];

const putCache = async (filePath) => {
try {
const fileContent = await fs.readFile(filePath, "utf8");
const hash = this.hash(fileContent);
this.cache.set(filePath, hash);
} catch (err) {
console.error("Cannot build cache, error reading file ", filePath);
throw err;
}
};

for (const filePath of filePaths) {
const fileExists = fsSync.existsSync(filePath);
if (!fileExists) continue;

promises.push(putCache(filePath));
}
const promises = filePaths
.filter((filePath) => fsSync.existsSync(filePath))
.map(async (filePath) => {
try {
const fileContent = await fs.readFile(filePath, "utf8");
const hash = this.hash(fileContent);
// Check if the file still exists and its content hasn't changed
// before setting the cache to avoid race conditions
const currentContent = await fs.readFile(filePath, "utf8");
if (currentContent === fileContent) {
this.cache.set(filePath, hash);
}
} catch (err) {
console.error("Cannot build cache, error reading file ", filePath);
// Don't throw here, allow other files to be processed
}
});

try {
await Promise.all(promises);
Expand Down
6 changes: 5 additions & 1 deletion compiler/mitosis.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const reactPlugin = require("./plugins/react.plugin");
const vuePlugin = require("./plugins/vue.plugin");

/**
* @type {import('@builder.io/mitosis').MitosisConfig}
Expand All @@ -13,8 +14,11 @@ module.exports = {
plugins: [reactPlugin],
},
vue: {
typescript: false,
typescript: true,
defineComponent: true,
namePrefix: "interchain",
api: "composition",
plugins: [vuePlugin],
},
},
};
Loading

0 comments on commit 29cd673

Please sign in to comment.