Skip to content

Commit

Permalink
Add experimental version for oxc-transformer usage
Browse files Browse the repository at this point in the history
  • Loading branch information
hamlim committed Sep 28, 2024
1 parent 178760d commit e0e7e6f
Show file tree
Hide file tree
Showing 16 changed files with 546 additions and 124 deletions.
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.8.0
Binary file modified bun.lockb
Binary file not shown.
20 changes: 19 additions & 1 deletion packages/hohoro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ Then add the following `dev` script to your `package.json`:
}
```

## Experimental:

This library also exposes a `hohoro-experimental` binary that builds code using [oxc](https://oxc.rs/) with [`oxc-transform`](https://www.npmjs.com/package/oxc-transform).

When using the experimental binary - you'll **need to also install `oxc-transform` as a devDependency**.

### Usage:

```json
{
"scripts": {
"build": "hohoro-experimental"
}
}
```

You **do not need additional configuration** when using the experimental build.

## Contributing:

### Code Quality:
Expand All @@ -62,7 +80,7 @@ This library uses [BiomeJS](https://biomejs.dev/) for linting, run `bun run lint

#### Tests

This library uses Node for running unit tests, run `bun run test` from the root or from this workspace!
This library uses Bun for running unit tests, run `bun run test` from the root or from this workspace!

### Publishing:

Expand Down
119 changes: 119 additions & 0 deletions packages/hohoro/__tests__/experimental-incremental-build.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { copyFileSync, rmSync, writeFileSync } from "node:fs";
import { dirname, join as pathJoin } from "node:path";
import { fileURLToPath } from "node:url";
import fg from "fast-glob";
import { runBuild } from "../experimental-incremental-build.mjs";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

describe("experimental hohoro", () => {
// copy over files from the template dir to the src dir
beforeEach(() => {
const templateDir = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"template",
);
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");
const files = fg.sync(pathJoin(templateDir, "**/*.{ts,tsx,js,json}"));

for (const file of files) {
const filePath = file.replace(templateDir, srcDir);
copyFileSync(file, filePath);
}
});

it("[experimental] It correctly builds the library", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};
await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);

expect(distFiles.some((file) => file.includes("tsx-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("tsx-file.d.ts"))).toBe(true);
expect(distFiles.some((file) => file.includes("js-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("json-file.json"))).toBe(
true,
);
expect(errors.length).toBe(0);
expect(logs[0]).toContain("compiled: 2 files, copied 1 file");
});

it("[experimental] It only builds changed files", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};

await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

// change a file
const tsxFile = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"src",
"tsx-file.tsx",
);
writeFileSync(tsxFile, `export const foo = 'bar';`);

await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

// most important assertion, only the tsx file should have been compiled!
expect(logs[1]).toContain("compiled: 1 file");

const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);

expect(distFiles.some((file) => file.includes("tsx-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("tsx-file.d.ts"))).toBe(true);
expect(distFiles.some((file) => file.includes("js-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("json-file.json"))).toBe(
true,
);
expect(errors.length).toBe(0);
});

// cleanup src and dist dirs after the tests run
afterEach(() => {
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");

const files = fg.sync(pathJoin(srcDir, "**/*.{ts,tsx,js,json}"));
for (const file of files) {
rmSync(file, { recursive: true });
}
rmSync(pathJoin(__dirname, "..", "sample-workspace-dir", "dist"), {
recursive: true,
});
});
});
215 changes: 99 additions & 116 deletions packages/hohoro/__tests__/incremental-build.test.mjs
Original file line number Diff line number Diff line change
@@ -1,139 +1,122 @@
import assert from "node:assert";
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { copyFileSync, rmSync, writeFileSync } from "node:fs";
import { dirname, join as pathJoin } from "node:path";
import { after, before, test } from "node:test";
import { fileURLToPath } from "node:url";
import fg from "fast-glob";
import { runBuild } from "../incremental-build.mjs";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// copy over files from the template dir to the src dir
before(() => {
const templateDir = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"template",
);
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");
const files = fg.sync(pathJoin(templateDir, "**/*.{ts,tsx,js,json}"));
describe("stable hohoro", () => {
// copy over files from the template dir to the src dir
beforeEach(() => {
const templateDir = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"template",
);
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");
const files = fg.sync(pathJoin(templateDir, "**/*.{ts,tsx,js,json}"));

for (const file of files) {
const filePath = file.replace(templateDir, srcDir);
copyFileSync(file, filePath);
}
});

test("It correctly builds the library", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};
await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
for (const file of files) {
const filePath = file.replace(templateDir, srcDir);
copyFileSync(file, filePath);
}
});

const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);
it("correctly builds the library", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};
await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

assert.ok(
distFiles.some((file) => file.includes("tsx-file.js")),
"Couldn't find tsx-file.js!",
);
assert.ok(
distFiles.some((file) => file.includes("tsx-file.d.ts")),
"Couldn't find tsx-file.d.ts!",
);
assert.ok(
distFiles.some((file) => file.includes("js-file.js")),
"Couldn't find js-file.js!",
);
assert.ok(
distFiles.some((file) => file.includes("json-file.json")),
"Couldn't find json-file.json!",
);
assert.equal(errors.length, 0, "There were errors logged during build!");
assert.ok(
logs[0].includes(`compiled: 2 files, copied 1 file`),
`Log message doesn't match!\n Received: ${logs[0]}`,
);
});
const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);

test("It only builds changed files", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};
expect(distFiles.some((file) => file.includes("tsx-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("tsx-file.d.ts"))).toBe(true);
expect(distFiles.some((file) => file.includes("js-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("json-file.json"))).toBe(
true,
);
expect(errors.length).toBe(0);
expect(logs[0]).toContain("compiled: 2 files, copied 1 file");
});

// change a file
const tsxFile = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"src",
"tsx-file.tsx",
);
writeFileSync(tsxFile, `export const foo = 'bar';`);
it("only builds changed files", async () => {
const logs = [];
const errors = [];
const logger = {
log(message) {
logs.push(message);
},
error(message) {
errors.push(message);
},
};

await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});
await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

// most important assertion, only the tsx file should have been compiled!
assert.ok(
logs[0].includes(`compiled: 1 file`),
`Log message doesn't match!\n Received: ${logs[0]}`,
);
// change a file
const tsxFile = pathJoin(
__dirname,
"..",
"sample-workspace-dir",
"src",
"tsx-file.tsx",
);
writeFileSync(tsxFile, `export const foo = 'baz';`);

const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);
await runBuild({
rootDirectory: pathJoin(__dirname, "..", "sample-workspace-dir"),
logger,
});

assert.ok(
distFiles.some((file) => file.includes("tsx-file.js")),
"Couldn't find tsx-file.js!",
);
assert.ok(
distFiles.some((file) => file.includes("tsx-file.d.ts")),
"Couldn't find tsx-file.d.ts!",
);
assert.ok(
distFiles.some((file) => file.includes("js-file.js")),
"Couldn't find js-file.js!",
);
assert.ok(
distFiles.some((file) => file.includes("json-file.json")),
"Couldn't find json-file.json!",
);
assert.equal(errors.length, 0, "There were errors logged during build!");
});
// logs[0] is the initial build
// logs[1] is the initial type def build
// logs[2] is the incremental rebuild
// most important assertion, only the tsx file should have been compiled!
expect(logs[2]).toContain("compiled: 1 file");

const distFiles = fg.sync(
pathJoin(__dirname, "..", "sample-workspace-dir", "dist", "**/*"),
);

expect(distFiles.some((file) => file.includes("tsx-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("tsx-file.d.ts"))).toBe(true);
expect(distFiles.some((file) => file.includes("js-file.js"))).toBe(true);
expect(distFiles.some((file) => file.includes("json-file.json"))).toBe(
true,
);
expect(errors.length).toBe(0);
});

// cleanup src and dist dirs after the tests run
after(() => {
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");
// cleanup src and dist dirs after the tests run
afterEach(() => {
const srcDir = pathJoin(__dirname, "..", "sample-workspace-dir", "src");

const files = fg.sync(pathJoin(srcDir, "**/*.{ts,tsx,js,json}"));
for (const file of files) {
rmSync(file, { recursive: true });
}
rmSync(pathJoin(__dirname, "..", "sample-workspace-dir", "dist"), {
recursive: true,
const files = fg.sync(pathJoin(srcDir, "**/*.{ts,tsx,js,json}"));
for (const file of files) {
rmSync(file, { recursive: true });
}
rmSync(pathJoin(__dirname, "..", "sample-workspace-dir", "dist"), {
recursive: true,
});
});
});
Loading

0 comments on commit e0e7e6f

Please sign in to comment.