Skip to content

Commit d87cc3b

Browse files
committed
use rolldown
1 parent 8f947ff commit d87cc3b

File tree

8 files changed

+956
-951
lines changed

8 files changed

+956
-951
lines changed

package-lock.json

Lines changed: 837 additions & 815 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,18 @@
4848
"@orama/orama": "^3.1.10",
4949
"@orama/plugin-data-persistence": "^3.1.10",
5050
"@orama/react-components": "^0.8.1",
51+
"@rollup/plugin-virtual": "^3.0.2",
5152
"acorn": "^8.15.0",
5253
"commander": "^14.0.0",
5354
"dedent": "^1.6.0",
54-
"esbuild": "^0.25.6",
55-
"esbuild-style-plugin": "^1.6.3",
5655
"estree-util-to-js": "^2.0.0",
5756
"estree-util-value-to-estree": "^3.4.0",
5857
"estree-util-visit": "^2.0.0",
5958
"github-slugger": "^2.0.0",
6059
"glob": "^11.0.3",
6160
"hast-util-to-string": "^3.0.1",
6261
"hastscript": "^9.0.1",
62+
"lightningcss": "^1.30.1",
6363
"mdast-util-slice-markdown": "^1.1.0",
6464
"mustache": "^4.2.0",
6565
"preact": "^10.26.9",
@@ -73,6 +73,7 @@
7373
"remark-parse": "^11.0.0",
7474
"remark-rehype": "^11.1.2",
7575
"remark-stringify": "^11.0.0",
76+
"rolldown": "^1.0.0-beta.24",
7677
"semver": "^7.7.1",
7778
"shiki": "^3.7.0",
7879
"unified": "^11.0.5",
Lines changed: 43 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,52 @@
1-
import { writeFile } from 'node:fs/promises';
1+
import virtual from '@rollup/plugin-virtual';
2+
import { build } from 'rolldown';
23

3-
import esbuild from 'esbuild';
4-
5-
import { RESOLVE_DIR } from '../constants.mjs';
4+
import cssLoader from './css.mjs';
65
import staticData from './data.mjs';
7-
import plugins from './plugins.mjs';
8-
9-
/** @typedef {{ server: boolean, debug: boolean }} BundleOptions */
10-
11-
/**
12-
* Creates the esbuild configuration object
13-
* @param {string} code - Source code to bundle
14-
* @param {BundleOptions} options - Options
15-
* @returns {import('esbuild').BuildOptions} ESBuild configuration
16-
*/
17-
const createConfig = (code, { server, debug }) => ({
18-
stdin: {
19-
contents: code,
20-
resolveDir: RESOLVE_DIR,
21-
loader: 'jsx',
22-
},
23-
bundle: true,
24-
minify: !debug,
25-
format: 'iife',
26-
platform: server ? 'node' : 'browser',
27-
jsx: 'automatic',
28-
write: false,
29-
outfile: 'output.js',
30-
// When updating the `define` object, also update client/types.d.ts to
31-
// include the newly defined globals
32-
define: {
33-
// Inject static data at build time
34-
__STATIC_DATA__: staticData,
35-
// Use `if (CLIENT)` or `if (SERVER)` to conditionally run code for specific environments,
36-
// and omit it otherwise. The `client/package.json` includes `sideEffects: false` to let
37-
// ESBuild safely tree-shake that directory. However, this doesn't affect dependencies,
38-
// so our tree-shaking ability is limited.
39-
//
40-
// TODO(@avivkeller): Consider switching to Rolldown once it's stable, as it offers
41-
// improved tree-shaking support, with the high-speed of ESBuild.
42-
SERVER: String(server),
43-
CLIENT: String(!server),
44-
},
45-
alias: {
46-
react: 'preact/compat',
47-
'react-dom': 'preact/compat',
48-
},
49-
external: server ? ['preact'] : [],
50-
plugins,
51-
metafile: debug,
52-
});
536

547
/**
558
* Bundles JavaScript code and returns JS/CSS content
569
* @param {string} code - Source code to bundle
57-
* @param {BundleOptions} options - Options
58-
* @returns {Promise<{js: string, css?: string}>}
10+
* @param {{ server: boolean }} options - Bundle configuration options
11+
* @returns {Promise<{ js: string, css: string }>} The bundled code
5912
*/
60-
export default async (code, { server = false, debug = false } = {}) => {
61-
const config = createConfig(code, { server, debug });
62-
const result = await esbuild.build(config);
63-
const [jsFile, cssFile] = result.outputFiles;
13+
export default async function bundle(code, { server = false } = {}) {
14+
const result = await build({
15+
input: 'entrypoint.jsx',
16+
output: {
17+
format: server ? 'cjs' : 'iife',
18+
minify: server ? undefined : true,
19+
},
20+
platform: server ? 'node' : 'browser',
21+
external: server ? ['preact'] : [],
22+
define: {
23+
// Inject static data at build time
24+
__STATIC_DATA__: staticData,
25+
26+
// Environment flags for conditional code
27+
// Use `if (CLIENT)` or `if (SERVER)` to target specific environments
28+
// The unused code will be removed during tree-shaking
29+
SERVER: String(server),
30+
CLIENT: String(!server),
31+
},
32+
jsx: 'react-jsx',
33+
resolve: {
34+
alias: {
35+
react: 'preact/compat',
36+
'react-dom': 'preact/compat',
37+
},
38+
},
39+
plugins: [
40+
virtual({
41+
'entrypoint.jsx': code,
42+
}),
43+
cssLoader(),
44+
],
45+
treeshake: true,
46+
write: false,
47+
});
6448

65-
if (debug) {
66-
await writeFile(
67-
`out/meta-${server ? 'server' : 'client'}.json`,
68-
JSON.stringify(result.metafile)
69-
);
70-
}
49+
const [js, ...cssFiles] = result.output;
7150

72-
return {
73-
js: jsFile.text,
74-
css: cssFile?.text,
75-
};
76-
};
51+
return { js: js.code, css: cssFiles.map(f => f.source).join('') };
52+
}

src/generators/web/build/css.mjs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { readFile } from 'node:fs/promises';
2+
3+
import { bundleAsync } from 'lightningcss';
4+
5+
/**
6+
* Rolldown plugin to compile `.module.css` files using lightningcss
7+
* and emit a single bundled CSS file.
8+
*
9+
* TODO(avivkeller): Once Rolldown supports CSS Modules natively, we
10+
* can remove this
11+
*
12+
* @returns {import('rolldown').Plugin}
13+
*/
14+
export default () => {
15+
const cssChunks = new Set();
16+
17+
return {
18+
name: 'css-loader',
19+
20+
/**
21+
* Handles loading and transforming CSS module files
22+
* @param {string} id - The file path being loaded
23+
*/
24+
async load(id) {
25+
if (!id.endsWith('.module.css')) {
26+
return null;
27+
}
28+
29+
const source = await readFile(id, 'utf8');
30+
31+
const { code, exports } = await bundleAsync({
32+
filename: id,
33+
code: Buffer.from(source),
34+
cssModules: true,
35+
});
36+
37+
cssChunks.add(code.toString());
38+
39+
const mappedExports = Object.fromEntries(
40+
Object.entries(exports).map(([k, v]) => [k, v.name])
41+
);
42+
43+
return {
44+
code: `export default ${JSON.stringify(mappedExports)};`,
45+
moduleType: 'js',
46+
};
47+
},
48+
49+
/**
50+
* Emits the collected CSS as a single file at the end of the build
51+
*/
52+
buildEnd() {
53+
if (cssChunks.size === 0) return;
54+
55+
this.emitFile({
56+
type: 'asset',
57+
name: 'styles.css',
58+
source: Array.from(cssChunks).join('\n'),
59+
});
60+
},
61+
};
62+
};

src/generators/web/build/generate.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export default () => {
4040
const buildClientProgram = componentCode => {
4141
return [
4242
...baseImports,
43-
createImportDeclaration(null, './index.css'),
43+
createImportDeclaration(
44+
null,
45+
new URL('../ui/index.css', import.meta.url).pathname
46+
),
4447
createImportDeclaration('hydrate', 'preact', false),
4548
'',
4649
`hydrate(${componentCode}, document.getElementById("root"));`,

src/generators/web/build/plugins.mjs

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/generators/web/constants.mjs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
1-
import { fileURLToPath } from 'node:url';
2-
3-
export const RESOLVE_DIR = fileURLToPath(new URL('./ui', import.meta.url));
4-
5-
// Imports are relative to RESOLVE_DIR, and must be complete paths (w/ file extensions)
61
export const JSX_IMPORTS = {
72
NavBar: {
83
name: 'NavBar',
9-
source: './components/NavBar.jsx',
4+
source: new URL('./ui/components/NavBar', import.meta.url).pathname,
105
},
116
SideBar: {
127
name: 'SideBar',
13-
source: './components/SideBar/index.jsx',
8+
source: new URL('./ui/components/SideBar', import.meta.url).pathname,
149
},
1510
MetaBar: {
1611
name: 'MetaBar',
17-
source: './components/MetaBar/index.jsx',
12+
source: new URL('./ui/components/MetaBar', import.meta.url).pathname,
1813
},
1914
CodeBox: {
2015
name: 'CodeBox',
21-
source: './components/CodeBox.jsx',
16+
source: new URL('./ui/components/CodeBox', import.meta.url).pathname,
2217
},
2318
CodeTabs: {
2419
name: 'CodeTabs',

src/generators/web/index.mjs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Mustache from 'mustache';
88

99
import bundleCode from './build/bundle.mjs';
1010
import createASTBuilder from './build/generate.mjs';
11-
import { RESOLVE_DIR } from './constants.mjs';
1211

1312
/**
1413
* Executes server-side code in a safe, isolated context
@@ -18,10 +17,11 @@ import { RESOLVE_DIR } from './constants.mjs';
1817
*/
1918
export async function executeServerCode(serverCode, require) {
2019
const { js: bundledServer } = await bundleCode(serverCode, { server: true });
20+
const variable = Math.random().toString(36).slice(2);
2121

2222
const executedFunction = new Function(
2323
'require',
24-
`let code;${bundledServer}return code;`
24+
`let ${variable};${bundledServer}return ${variable};`
2525
);
2626

2727
return executedFunction(require);
@@ -105,7 +105,7 @@ export default {
105105
'utf-8'
106106
);
107107
const astBuilders = createASTBuilder();
108-
const require = createRequire(RESOLVE_DIR);
108+
const require = createRequire(import.meta.url);
109109

110110
// Process all entries
111111
const results = [];

0 commit comments

Comments
 (0)