Skip to content

Commit b992437

Browse files
committed
Modernize and simplify our packages building tools, replace Rollup by tsup
1 parent 61d79b6 commit b992437

File tree

4 files changed

+582
-256
lines changed

4 files changed

+582
-256
lines changed

bin/build_package.ts

Lines changed: 93 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
import * as fs from 'node:fs';
66
import * as path from 'node:path';
77
import { parseArgs } from 'node:util';
8-
import * as LightningCSS from 'lightningcss';
9-
import * as rollup from 'rollup';
108
import { globSync } from 'tinyglobby';
11-
import { getRollupConfiguration } from './rollup.ts';
9+
import { build } from 'tsup';
10+
import { readPackageJSON } from "pkg-types";
1211

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

37-
const packageData = await import(path.join(packageRoot, 'package.json'), {with: { type: 'json'}});
38-
const packageName = packageData.name;
39-
const srcDir = path.join(packageRoot, 'src');
40-
const distDir = path.join(packageRoot, 'dist');
36+
const packageData = await readPackageJSON(path.join(packageRoot, 'package.json'));
4137

42-
if (!fs.existsSync(srcDir)) {
43-
console.error(`The package directory "${packageRoot}" does not contain a "src" directory.`);
44-
process.exit(1);
45-
}
46-
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 = [
54-
...globSync(path.join(srcDir, '*controller.ts')),
55-
...(['@symfony/ux-react', '@symfony/ux-vue', '@symfony/ux-svelte'].includes(packageName)
56-
? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'components.ts')]
38+
const inputCssFile = packageData?.config?.css_source;
39+
const inputFiles = [
40+
...globSync('src/*controller.ts'),
41+
...(['@symfony/ux-react', '@symfony/ux-vue', '@symfony/ux-svelte'].includes(packageData.name)
42+
? ['src/loader.ts', 'src/components.ts']
5743
: []),
58-
...(packageName === '@symfony/stimulus-bundle'
59-
? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'controllers.ts')]
44+
...(packageData.name === '@symfony/stimulus-bundle'
45+
? ['src/loader.ts', 'src/controllers.ts']
6046
: []),
47+
...(inputCssFile ? [inputCssFile] : []),
6148
];
6249

63-
const inputStyleFile = packageData.config?.css_source;
64-
const buildCss = async () => {
65-
if (!inputStyleFile) {
66-
return;
50+
const external = new Set([
51+
// We force "dependencies" and "peerDependencies" to be external to avoid bundling them.
52+
...Object.keys(packageData.dependencies || {}),
53+
...Object.keys(packageData.peerDependencies || {}),
54+
]);
55+
56+
inputFiles.forEach((file) => {
57+
// custom handling for StimulusBundle
58+
if (file.includes('StimulusBundle/assets/src/loader.ts')) {
59+
external.add('./controllers.js');
6760
}
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-
};
80-
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-
}
8761

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-
],
62+
// React, Vue, Svelte
63+
if (file.includes('assets/src/loader.ts')) {
64+
external.add('./components.js');
65+
}
10466
});
10567

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...');
124-
}
125-
126-
if (inputStyleFile && id === inputStyleFile) {
127-
await buildCss();
68+
await build({
69+
entry: inputFiles,
70+
outDir: path.join(packageRoot, 'dist'),
71+
clean: true,
72+
external: Array.from(external),
73+
format: 'esm',
74+
platform: 'browser',
75+
tsconfig: path.join(import.meta.dirname, '../tsconfig.packages.json'),
76+
dts: {
77+
entry: inputFiles.filter(inputFile => !inputFile.endsWith('.css')),
78+
},
79+
watch: isWatch,
80+
splitting: false,
81+
esbuildOptions(options) {
82+
// Disabling `bundle` option prevent esbuild to inline relative (but external) imports (like "./components.js" for React, Vue, Svelte).
83+
options.bundle = false;
84+
},
85+
plugins: [
86+
{
87+
/**
88+
* This plugin is used to minify CSS files using LightningCSS.
89+
*
90+
* Even if tsup supports CSS minification through ESBuild by setting the `minify: true` option,
91+
* it also minifies JS files but we don't want that.
92+
*/
93+
name: 'symfony-ux:minify-css',
94+
async renderChunk(code, chunkInfo) {
95+
if (!/\.css$/.test(chunkInfo.path)) {
96+
return null;
97+
}
98+
99+
const { transform } = await import('lightningcss');
100+
const result = transform({
101+
filename: chunkInfo.path,
102+
code: Buffer.from(code),
103+
minify: true,
104+
});
105+
106+
console.log(`[Symfony UX] Minified CSS file: ${chunkInfo.path}`);
107+
108+
return {
109+
code: result.code.toString(),
110+
map: result.map ? result.map.toString() : null,
111+
}
112+
},
113+
},
114+
115+
/**
116+
* Unlike tsdown/rolldown and the option "cssEntryFileNames", tsup does not support
117+
* customizing the output file names for CSS files.
118+
* A plugin is needed to rename the written CSS files to add the ".min" suffix.
119+
*/
120+
{
121+
name: 'symfony-ux:append-min-to-css',
122+
async buildEnd({ writtenFiles }) {
123+
for (const writtenFile of writtenFiles) {
124+
if (!writtenFile.name.endsWith('.css')) {
125+
continue;
126+
}
127+
128+
const newName = writtenFile.name.replace(/\.css$/, '.min.css');
129+
await fs.promises.rename(writtenFile.name, newName);
130+
131+
console.info(`[Symfony UX] Renamed ${writtenFile.name} to ${newName}`);
132+
}
133+
}
128134
}
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);
139-
}
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-
}
135+
],
136+
});
148137
}
149138

150139
main();

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",
2017
"@testing-library/dom": "catalog:",
2118
"@testing-library/jest-dom": "catalog:",
2219
"@types/node": "^22.6.0",
2320
"lightningcss": "^1.28.2",
21+
"pkg-types": "^2.2.0",
2422
"playwright": "^1.47.0",
25-
"rollup": "^4.44.1",
2623
"tinyglobby": "^0.2.14",
24+
"tsup": "^8.5.0",
2725
"vitest": "catalog:"
2826
},
2927
"version": "2.27.0"

0 commit comments

Comments
 (0)