Skip to content

Commit 13e1bef

Browse files
committed
Make building tool easier, drop Rollup & cie for tsdown
1 parent 45f31cc commit 13e1bef

File tree

5 files changed

+451
-367
lines changed

5 files changed

+451
-367
lines changed

bin/build_package.ts

Lines changed: 62 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import * as fs from 'node:fs';
66
import * as path from 'node:path';
77
import { parseArgs } from 'node:util';
88
import * as LightningCSS from 'lightningcss';
9-
import * as rollup from 'rollup';
109
import { globSync } from 'tinyglobby';
11-
import { getRollupConfiguration } from './rollup.ts';
10+
import { build } from 'tsdown';
1211

1312
const args = parseArgs({
1413
allowPositionals: true,
@@ -34,7 +33,7 @@ async function main() {
3433
process.exit(1);
3534
}
3635

37-
const packageData = await import(path.join(packageRoot, 'package.json'), {with: { type: 'json'}});
36+
const packageData = await import(path.join(packageRoot, 'package.json'), { with: { type: 'json' } });
3837
const packageName = packageData.name;
3938
const srcDir = path.join(packageRoot, 'src');
4039
const distDir = path.join(packageRoot, 'dist');
@@ -44,107 +43,82 @@ async function main() {
4443
process.exit(1);
4544
}
4645

47-
if (fs.existsSync(distDir)) {
48-
console.log(`Cleaning up the "${distDir}" directory...`);
49-
await fs.promises.rm(distDir, { recursive: true });
50-
await fs.promises.mkdir(distDir);
51-
}
52-
53-
const inputScriptFiles = [
46+
const inputFiles = [
5447
...globSync(path.join(srcDir, '*controller.ts')),
5548
...(['@symfony/ux-react', '@symfony/ux-vue', '@symfony/ux-svelte'].includes(packageName)
5649
? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'components.ts')]
5750
: []),
5851
...(packageName === '@symfony/stimulus-bundle'
5952
? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'controllers.ts')]
6053
: []),
54+
...(packageData?.config?.css_source ? [packageData.config.css_source] : []),
6155
];
6256

63-
const inputStyleFile = packageData.config?.css_source;
64-
const buildCss = async () => {
65-
if (!inputStyleFile) {
66-
return;
67-
}
68-
const inputStyleFileDist = path.resolve(distDir, `${path.basename(inputStyleFile, '.css')}.min.css`);
69-
70-
console.log('Minifying CSS...');
71-
const css = await fs.promises.readFile(inputStyleFile, 'utf-8');
72-
const { code: minified } = LightningCSS.transform({
73-
filename: path.basename(inputStyleFile, '.css'),
74-
code: Buffer.from(css),
75-
minify: true,
76-
sourceMap: false, // TODO: Maybe we can add source maps later? :)
77-
});
78-
await fs.promises.writeFile(inputStyleFileDist, minified);
79-
};
57+
const peerDependencies = [
58+
'@hotwired/stimulus',
59+
...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : []),
60+
];
8061

81-
if (inputScriptFiles.length === 0) {
82-
console.error(
83-
`No input files found for package "${packageName}" (directory "${packageRoot}").\nEnsure you have at least a file matching the pattern "src/*_controller.ts", or manually specify input files in "${import.meta.filename}" file.`
84-
);
85-
process.exit(1);
86-
}
62+
inputFiles.forEach((file) => {
63+
// custom handling for StimulusBundle
64+
if (file.includes('StimulusBundle/assets/src/loader.ts')) {
65+
peerDependencies.push('./controllers.js');
66+
}
8767

88-
const rollupConfig = getRollupConfiguration({
89-
packageRoot,
90-
inputFiles: inputScriptFiles,
91-
isWatch,
92-
additionalPlugins: [
93-
...(isWatch && inputStyleFile
94-
? [
95-
{
96-
name: 'watcher',
97-
buildStart(this: rollup.PluginContext) {
98-
this.addWatchFile(inputStyleFile);
99-
},
100-
},
101-
]
102-
: []),
103-
],
68+
// React, Vue
69+
if (file.includes('assets/src/loader.ts')) {
70+
peerDependencies.push('./components.js');
71+
}
10472
});
10573

106-
if (isWatch) {
107-
console.log(
108-
`Watching for JavaScript${inputStyleFile ? ' and CSS' : ''} files modifications in "${srcDir}" directory...`
109-
);
110-
111-
const watcher = rollup.watch(rollupConfig);
112-
watcher.on('event', (event) => {
113-
if (event.code === 'ERROR') {
114-
console.error('Error during build:', event.error);
115-
}
116-
117-
if ((event.code === 'BUNDLE_END' || event.code === 'ERROR') && event.result) {
118-
event.result.close();
119-
}
120-
});
121-
watcher.on('change', async (id, { event }) => {
122-
if (event === 'update') {
123-
console.log('Files were modified, rebuilding...');
74+
build({
75+
entry: inputFiles,
76+
outDir: distDir,
77+
clean: true,
78+
outputOptions: {
79+
cssEntryFileNames: '[name].min.css',
80+
},
81+
external: peerDependencies,
82+
format: 'esm',
83+
platform: 'browser',
84+
tsconfig: path.join(import.meta.dirname, '../tsconfig.packages.json'),
85+
// The target should be kept in sync with `tsconfig.packages.json` file.
86+
// In the future, I hope the target will be read from the `tsconfig.packages.json` file, but for now we need to specify it manually.
87+
target: 'es2021',
88+
watch: isWatch,
89+
plugins: [
90+
{
91+
name: 'minimize-css',
92+
transform: {
93+
filter: {
94+
id: /\.css$/,
95+
},
96+
handler (code, id) {
97+
const { code: minifiedCode } = LightningCSS.transform({
98+
filename: path.basename(id),
99+
code: Buffer.from(code),
100+
minify: true,
101+
sourceMap: false,
102+
});
103+
104+
return { code: minifiedCode.toString(), map: null };
105+
}
106+
},
124107
}
125-
126-
if (inputStyleFile && id === inputStyleFile) {
127-
await buildCss();
108+
],
109+
hooks: {
110+
async 'build:done'() {
111+
// TODO: Idk why, but when we build a CSS file (e.g. `style.css`), it also generate an empty JS file (e.g. `style.js`).
112+
if (packageData?.config?.css_source) {
113+
const unwantedJsFile = path.join(distDir, path.basename(packageData.config.css_source, '.css') + '.js');
114+
await fs.promises.rm(unwantedJsFile, { force: true });
115+
}
128116
}
129-
});
130-
} else {
131-
console.log(`Building JavaScript files from ${packageName} package...`);
132-
const start = Date.now();
133-
134-
if (typeof rollupConfig.output === 'undefined' || Array.isArray(rollupConfig.output)) {
135-
console.error(
136-
`The rollup configuration for package "${packageName}" does not contain a valid output configuration.`
137-
);
138-
process.exit(1);
139117
}
140-
141-
const bundle = await rollup.rollup(rollupConfig);
142-
await bundle.write(rollupConfig.output);
143-
144-
await buildCss();
145-
146-
console.log(`Done in ${((Date.now() - start) / 1000).toFixed(3)} seconds.`);
147-
}
118+
}).catch((error) => {
119+
console.error('Error during build:', error);
120+
process.exit(1);
121+
});
148122
}
149123

150124
main();

bin/rollup.ts

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

package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,14 @@
1414
},
1515
"devDependencies": {
1616
"@biomejs/biome": "^2.0.4",
17-
"@rollup/plugin-commonjs": "^28.0.6",
18-
"@rollup/plugin-node-resolve": "^16.0.1",
19-
"@rollup/plugin-typescript": "^12.1.4",
17+
"@oxc-project/runtime": "^0.77.3",
2018
"@testing-library/dom": "catalog:",
2119
"@testing-library/jest-dom": "catalog:",
2220
"@types/node": "^22.6.0",
2321
"lightningcss": "^1.28.2",
2422
"playwright": "^1.47.0",
25-
"rollup": "^4.44.1",
2623
"tinyglobby": "^0.2.14",
24+
"tsdown": "^0.12.9",
2725
"vitest": "catalog:"
2826
},
2927
"version": "2.27.0"

0 commit comments

Comments
 (0)