From d15e2eaf116c0f22930291a187bc394a6bb792f2 Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Wed, 19 Nov 2025 14:36:44 -0800 Subject: [PATCH 1/7] feat: separate minify from build, generate separate bundles --- charts/legend/package.json | 16 ++++-- charts/legend/rollup.config.mjs | 17 +++++++ pnpm-lock.yaml | 3 ++ tools/build/config/rollup.config.mjs | 2 +- tools/build/package.json | 1 + tools/build/src/cli-commands.ts | 13 +++++ tools/build/src/cli.ts | 2 + tools/build/src/index.ts | 2 + tools/build/src/minify.ts | 73 ++++++++++++++++++++++++++++ tools/cli/src/index.ts | 2 + 10 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 charts/legend/rollup.config.mjs create mode 100644 tools/build/src/minify.ts diff --git a/charts/legend/package.json b/charts/legend/package.json index de6383703d..4a322f9cbf 100644 --- a/charts/legend/package.json +++ b/charts/legend/package.json @@ -7,7 +7,7 @@ "types": "./dist/types/index.d.ts", "license": "Apache-2.0", "scripts": { - "build": "lg-build bundle", + "build": "lg-build bundle && lg-build minify", "tsc": "lg-build tsc", "docs": "lg-build docs" }, @@ -41,8 +41,18 @@ ".": { "types": "./dist/types/index.d.ts", "types@<=5.0": "./dist/types/ts4.9/index.d.ts", - "import": "./dist/esm/index.js", - "require": "./dist/umd/index.js" + "import": { + "browser": { + "production": "./dist/esm/index-min.js" + }, + "default": "./dist/esm/index.js" + }, + "require": { + "browser": { + "production": "./dist/umd/index-min.js" + }, + "default": "./dist/umd/index.js" + } } }, "typesVersions": {} diff --git a/charts/legend/rollup.config.mjs b/charts/legend/rollup.config.mjs new file mode 100644 index 0000000000..cdbf543650 --- /dev/null +++ b/charts/legend/rollup.config.mjs @@ -0,0 +1,17 @@ +import defaultConfig, { + esmConfig, + umdConfig, +} from '@lg-tools/build/config/rollup.config.mjs'; + +const esmConstantsConfig = { + ...esmConfig, + // remove terser plugin + plugins: [...esmConfig.plugins.filter(plugin => plugin.name !== 'terser')], +}; +const umdConstantsConfig = { + ...umdConfig, + // remove terser plugin + plugins: [...umdConfig.plugins.filter(plugin => plugin.name !== 'terser')], +}; + +export default [...defaultConfig, esmConstantsConfig, umdConstantsConfig]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e048eb7d6e..9b73faae81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3902,6 +3902,9 @@ importers: rollup-plugin-polyfill-node: specifier: 0.13.0 version: 0.13.0(rollup@4.16.1) + terser: + specifier: ^5.43.1 + version: 5.43.1 turbo: specifier: ^2.0.6 version: 2.5.5 diff --git a/tools/build/config/rollup.config.mjs b/tools/build/config/rollup.config.mjs index 400887c21c..65b88d212c 100644 --- a/tools/build/config/rollup.config.mjs +++ b/tools/build/config/rollup.config.mjs @@ -63,7 +63,7 @@ const createConfigForFormat = (format, overrides) => { babelHelpers: 'bundled', extensions, configFile: babelConfigPath, - sourceMaps: 'inline', + sourceMaps: true, envName: 'production', }), diff --git a/tools/build/package.json b/tools/build/package.json index 74dae3bccf..f7d98192f4 100644 --- a/tools/build/package.json +++ b/tools/build/package.json @@ -48,6 +48,7 @@ "rollup-plugin-bundle-stats": "^4.18.2", "rollup-plugin-node-externals": "7.1.1", "rollup-plugin-polyfill-node": "0.13.0", + "terser": "^5.43.1", "typescript": "~5.8.0" }, "peerDependencies": { diff --git a/tools/build/src/cli-commands.ts b/tools/build/src/cli-commands.ts index 1beb6ea259..65add52248 100644 --- a/tools/build/src/cli-commands.ts +++ b/tools/build/src/cli-commands.ts @@ -3,6 +3,7 @@ import { Command } from 'commander'; import { buildPackage } from './rollup/build-package'; import { buildTSDoc } from './tsdoc/build-tsdoc'; import { buildTypescript } from './typescript/build-ts'; +import { minifyPackage } from './minify'; export function registerBundleCommand(command: Command) { command @@ -36,3 +37,15 @@ export function registerBuildDocsCommand(command: Command) { .option('-v, --verbose', 'Enable verbose logging', false) .action(buildTSDoc); } + +export function registerMinifyCommand(command: Command) { + command + .description('Minify built JavaScript bundles') + .option( + '-p, --glob ', + 'Glob pattern to match javascript files to minify, prefixed with ! to exclude', + ['dist/**/*.*js', '!dist/**/*-min.*js'], + ) + .option('-v, --verbose', 'Enable verbose logging', false) + .action(minifyPackage); +} diff --git a/tools/build/src/cli.ts b/tools/build/src/cli.ts index 1aecd7ebbb..61ca7abcac 100644 --- a/tools/build/src/cli.ts +++ b/tools/build/src/cli.ts @@ -4,6 +4,7 @@ import { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, + registerMinifyCommand, } from './cli-commands'; const build = new Command('lg-build'); @@ -12,5 +13,6 @@ build.description('Build LeafyGreen packages'); registerBundleCommand(build.command('bundle')); registerBuildTSCommand(build.command('tsc')); registerBuildDocsCommand(build.command('docs')); +registerMinifyCommand(build.command('minify')); build.parse(process.argv); diff --git a/tools/build/src/index.ts b/tools/build/src/index.ts index 9246e60a82..21dd00f7b9 100644 --- a/tools/build/src/index.ts +++ b/tools/build/src/index.ts @@ -3,7 +3,9 @@ export { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, + registerMinifyCommand, } from './cli-commands'; +export { minifyPackage } from './minify'; export { buildPackage } from './rollup/build-package'; export { buildTSDoc } from './tsdoc/build-tsdoc'; export { parseTSDoc } from './tsdoc/tsdocParser'; diff --git a/tools/build/src/minify.ts b/tools/build/src/minify.ts new file mode 100644 index 0000000000..bf2418a8cc --- /dev/null +++ b/tools/build/src/minify.ts @@ -0,0 +1,73 @@ +/* eslint-disable no-console */ +import fs from 'fs'; +import { glob } from 'glob'; +import path from 'path'; +import { minify_sync } from 'terser'; + +interface MinifyOptions { + verbose: boolean; + glob: Array; +} + +export function minifyPackage({ verbose, glob: globPatterns }: MinifyOptions) { + // Find all compiled JavaScript files in dist directories for this package + // Exclude already minified files (e.g., `*-min.js`) + const [include, exclude] = [ + globPatterns.filter(g => !g.startsWith('!')), + globPatterns.filter(g => g.startsWith('!')).map(g => g.slice(1)), + ]; + + const jsFiles = glob.sync(include, { + ignore: exclude, + }); + + if (verbose) { + console.log('Found JavaScript files to minify:', jsFiles); + } + + for (const jsFile of jsFiles) { + const dir = path.dirname(jsFile); + const ext = path.extname(jsFile); + const name = path.basename(jsFile, ext); + const existingSourceMapFile = path.join(dir, `${name}${ext}.map`); + const minifiedFile = path.join(dir, `${name}-min${ext}`); + const minifiedFileMap = path.join(dir, `${name}-min${ext}.map`); + + try { + if (verbose) { + console.log(`Minifying ${jsFile} -> ${minifiedFile}`); + } + + const fileContent = fs.readFileSync(jsFile, 'utf8'); + const existingSourceMapContent = fs.readFileSync( + existingSourceMapFile, + 'utf8', + ); + + const isEsm = ext === '.mjs' || jsFile.includes('/esm/') || undefined; + + const minified = minify_sync(fileContent, { + sourceMap: { + filename: path.basename(minifiedFile), + content: existingSourceMapContent, + url: path.basename(minifiedFileMap), + }, + module: isEsm, + compress: true, + mangle: true, + }); + + fs.writeFileSync(minifiedFile, minified.code!); + fs.writeFileSync(minifiedFileMap, minified.map! as string); + + if (verbose) { + console.log(`✓ Minified ${jsFile}`); + } + } catch (error) { + console.error(`✗ Failed to minify ${jsFile}:`, error); + throw error; + } + } + + console.log(`✓ Minified ${jsFiles.length} javascript files.`); +} diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index 06a6160e39..2913125366 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -2,6 +2,7 @@ import { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, + registerMinifyCommand, } from '@lg-tools/build'; import { migrator } from '@lg-tools/codemods'; import { createPackage } from '@lg-tools/create'; @@ -244,6 +245,7 @@ cli registerBundleCommand(cli.command('build-package')); registerBuildTSCommand(cli.command('build-ts')); registerBuildDocsCommand(cli.command('build-tsdoc')); +registerMinifyCommand(cli.command('build-minify')); /** Merge editor settings */ cli From 8836660fd302662af710ce7d4282530790d8fc37 Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Wed, 19 Nov 2025 15:17:29 -0800 Subject: [PATCH 2/7] docs: add changeset --- .changeset/blue-laws-tie.md | 5 +++++ .changeset/breezy-groups-turn.md | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 .changeset/blue-laws-tie.md create mode 100644 .changeset/breezy-groups-turn.md diff --git a/.changeset/blue-laws-tie.md b/.changeset/blue-laws-tie.md new file mode 100644 index 0000000000..276dc36d00 --- /dev/null +++ b/.changeset/blue-laws-tie.md @@ -0,0 +1,5 @@ +--- +'@lg-charts/legend': minor +--- + +Updated `@lg-charts/legend` package build configuration to generate both non-minified and minified bundles. The default export is now the non-minified bundle, with the minified bundle provided as a production-specific export. diff --git a/.changeset/breezy-groups-turn.md b/.changeset/breezy-groups-turn.md new file mode 100644 index 0000000000..1df714e510 --- /dev/null +++ b/.changeset/breezy-groups-turn.md @@ -0,0 +1,8 @@ +--- +'@lg-tools/build': minor +'@lg-tools/cli': minor +--- + +Introduced new `lg build-minify` and `lg-build minify` commands to separately minify JavaScript bundle files. +Files to be minified can be specified using the `--glob` argument (default: `--glob=dist/**/*.*js --glob=!dist/**/*-min.*js`). +This allows generating both minified and non-minified bundles in the same package for use in different environments, decoupling minification from the main build process. \ No newline at end of file From 860ee082d8afa5ad1b2653b68eb0a01014079d53 Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Mon, 24 Nov 2025 11:38:21 -0800 Subject: [PATCH 3/7] undo: the old approach --- charts/legend/package.json | 2 +- pnpm-lock.yaml | 3 -- tools/build/package.json | 1 - tools/build/src/cli-commands.ts | 13 ------ tools/build/src/cli.ts | 2 - tools/build/src/index.ts | 2 - tools/build/src/minify.ts | 73 --------------------------------- tools/cli/src/index.ts | 2 - 8 files changed, 1 insertion(+), 97 deletions(-) delete mode 100644 tools/build/src/minify.ts diff --git a/charts/legend/package.json b/charts/legend/package.json index 4a322f9cbf..f03e4dcbcb 100644 --- a/charts/legend/package.json +++ b/charts/legend/package.json @@ -7,7 +7,7 @@ "types": "./dist/types/index.d.ts", "license": "Apache-2.0", "scripts": { - "build": "lg-build bundle && lg-build minify", + "build": "lg-build bundle", "tsc": "lg-build tsc", "docs": "lg-build docs" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b73faae81..e048eb7d6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3902,9 +3902,6 @@ importers: rollup-plugin-polyfill-node: specifier: 0.13.0 version: 0.13.0(rollup@4.16.1) - terser: - specifier: ^5.43.1 - version: 5.43.1 turbo: specifier: ^2.0.6 version: 2.5.5 diff --git a/tools/build/package.json b/tools/build/package.json index f7d98192f4..74dae3bccf 100644 --- a/tools/build/package.json +++ b/tools/build/package.json @@ -48,7 +48,6 @@ "rollup-plugin-bundle-stats": "^4.18.2", "rollup-plugin-node-externals": "7.1.1", "rollup-plugin-polyfill-node": "0.13.0", - "terser": "^5.43.1", "typescript": "~5.8.0" }, "peerDependencies": { diff --git a/tools/build/src/cli-commands.ts b/tools/build/src/cli-commands.ts index 65add52248..1beb6ea259 100644 --- a/tools/build/src/cli-commands.ts +++ b/tools/build/src/cli-commands.ts @@ -3,7 +3,6 @@ import { Command } from 'commander'; import { buildPackage } from './rollup/build-package'; import { buildTSDoc } from './tsdoc/build-tsdoc'; import { buildTypescript } from './typescript/build-ts'; -import { minifyPackage } from './minify'; export function registerBundleCommand(command: Command) { command @@ -37,15 +36,3 @@ export function registerBuildDocsCommand(command: Command) { .option('-v, --verbose', 'Enable verbose logging', false) .action(buildTSDoc); } - -export function registerMinifyCommand(command: Command) { - command - .description('Minify built JavaScript bundles') - .option( - '-p, --glob ', - 'Glob pattern to match javascript files to minify, prefixed with ! to exclude', - ['dist/**/*.*js', '!dist/**/*-min.*js'], - ) - .option('-v, --verbose', 'Enable verbose logging', false) - .action(minifyPackage); -} diff --git a/tools/build/src/cli.ts b/tools/build/src/cli.ts index 61ca7abcac..1aecd7ebbb 100644 --- a/tools/build/src/cli.ts +++ b/tools/build/src/cli.ts @@ -4,7 +4,6 @@ import { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, - registerMinifyCommand, } from './cli-commands'; const build = new Command('lg-build'); @@ -13,6 +12,5 @@ build.description('Build LeafyGreen packages'); registerBundleCommand(build.command('bundle')); registerBuildTSCommand(build.command('tsc')); registerBuildDocsCommand(build.command('docs')); -registerMinifyCommand(build.command('minify')); build.parse(process.argv); diff --git a/tools/build/src/index.ts b/tools/build/src/index.ts index 21dd00f7b9..9246e60a82 100644 --- a/tools/build/src/index.ts +++ b/tools/build/src/index.ts @@ -3,9 +3,7 @@ export { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, - registerMinifyCommand, } from './cli-commands'; -export { minifyPackage } from './minify'; export { buildPackage } from './rollup/build-package'; export { buildTSDoc } from './tsdoc/build-tsdoc'; export { parseTSDoc } from './tsdoc/tsdocParser'; diff --git a/tools/build/src/minify.ts b/tools/build/src/minify.ts deleted file mode 100644 index bf2418a8cc..0000000000 --- a/tools/build/src/minify.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable no-console */ -import fs from 'fs'; -import { glob } from 'glob'; -import path from 'path'; -import { minify_sync } from 'terser'; - -interface MinifyOptions { - verbose: boolean; - glob: Array; -} - -export function minifyPackage({ verbose, glob: globPatterns }: MinifyOptions) { - // Find all compiled JavaScript files in dist directories for this package - // Exclude already minified files (e.g., `*-min.js`) - const [include, exclude] = [ - globPatterns.filter(g => !g.startsWith('!')), - globPatterns.filter(g => g.startsWith('!')).map(g => g.slice(1)), - ]; - - const jsFiles = glob.sync(include, { - ignore: exclude, - }); - - if (verbose) { - console.log('Found JavaScript files to minify:', jsFiles); - } - - for (const jsFile of jsFiles) { - const dir = path.dirname(jsFile); - const ext = path.extname(jsFile); - const name = path.basename(jsFile, ext); - const existingSourceMapFile = path.join(dir, `${name}${ext}.map`); - const minifiedFile = path.join(dir, `${name}-min${ext}`); - const minifiedFileMap = path.join(dir, `${name}-min${ext}.map`); - - try { - if (verbose) { - console.log(`Minifying ${jsFile} -> ${minifiedFile}`); - } - - const fileContent = fs.readFileSync(jsFile, 'utf8'); - const existingSourceMapContent = fs.readFileSync( - existingSourceMapFile, - 'utf8', - ); - - const isEsm = ext === '.mjs' || jsFile.includes('/esm/') || undefined; - - const minified = minify_sync(fileContent, { - sourceMap: { - filename: path.basename(minifiedFile), - content: existingSourceMapContent, - url: path.basename(minifiedFileMap), - }, - module: isEsm, - compress: true, - mangle: true, - }); - - fs.writeFileSync(minifiedFile, minified.code!); - fs.writeFileSync(minifiedFileMap, minified.map! as string); - - if (verbose) { - console.log(`✓ Minified ${jsFile}`); - } - } catch (error) { - console.error(`✗ Failed to minify ${jsFile}:`, error); - throw error; - } - } - - console.log(`✓ Minified ${jsFiles.length} javascript files.`); -} diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index 2913125366..06a6160e39 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -2,7 +2,6 @@ import { registerBuildDocsCommand, registerBuildTSCommand, registerBundleCommand, - registerMinifyCommand, } from '@lg-tools/build'; import { migrator } from '@lg-tools/codemods'; import { createPackage } from '@lg-tools/create'; @@ -245,7 +244,6 @@ cli registerBundleCommand(cli.command('build-package')); registerBuildTSCommand(cli.command('build-ts')); registerBuildDocsCommand(cli.command('build-tsdoc')); -registerMinifyCommand(cli.command('build-minify')); /** Merge editor settings */ cli From 04104e597dfbaed42e6edd1ae4eb6d446f9b2089 Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Mon, 24 Nov 2025 11:42:33 -0800 Subject: [PATCH 4/7] feat: use single rollup config with multiple outputs --- charts/legend/rollup.config.mjs | 19 ++---- tools/build/config/rollup.config.mjs | 90 +++++++++++++++++++--------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/charts/legend/rollup.config.mjs b/charts/legend/rollup.config.mjs index cdbf543650..880853e7de 100644 --- a/charts/legend/rollup.config.mjs +++ b/charts/legend/rollup.config.mjs @@ -1,17 +1,6 @@ -import defaultConfig, { - esmConfig, - umdConfig, +import { + storiesConfig, + modernDevProdConfig, } from '@lg-tools/build/config/rollup.config.mjs'; -const esmConstantsConfig = { - ...esmConfig, - // remove terser plugin - plugins: [...esmConfig.plugins.filter(plugin => plugin.name !== 'terser')], -}; -const umdConstantsConfig = { - ...umdConfig, - // remove terser plugin - plugins: [...umdConfig.plugins.filter(plugin => plugin.name !== 'terser')], -}; - -export default [...defaultConfig, esmConstantsConfig, umdConstantsConfig]; +export default [storiesConfig, modernDevProdConfig]; diff --git a/tools/build/config/rollup.config.mjs b/tools/build/config/rollup.config.mjs index 65b88d212c..0eddd2eeff 100644 --- a/tools/build/config/rollup.config.mjs +++ b/tools/build/config/rollup.config.mjs @@ -36,40 +36,49 @@ const moduleFormatToDirectory = { const doTestUtilsExist = glob.sync(testUtilsFilename).length > 0; /** - * - * @param {'esm' | 'umd'} format - * @param {*} overrides - * @returns + * @param {{ format: import('rollup').OutputOptions['format'], useTerser?: boolean, outputNameSuffix?: string }} options + * @returns {import('rollup').OutputOptions} */ -const createConfigForFormat = (format, overrides) => { +const createOutput = ({ format, useTerser = false, outputNameSuffix = '' }) => { + return { + dir: moduleFormatToDirectory[format], + name, + format, + sourcemap: true, + globals: format === 'umd' ? getUMDGlobals() : {}, + validate: true, + interop: 'compat', // https://rollupjs.org/configuration-options/#output-interop + entryFileNames: `[name]${outputNameSuffix}.js`, + plugins: useTerser ? [terser()] : [], + }; +}; + +/** + * @param {import('rollup').OutputOptions} output + * @param {Partial} [overrides] + * @returns {import('rollup').RollupOptions} + */ +const createConfigForFormat = (output, overrides = {}) => { + /** @type {import('@rollup/plugin-babel').RollupBabelInputPluginOptions} */ + const babelOptions = { + babelrc: false, + babelHelpers: 'bundled', + extensions, + configFile: babelConfigPath, + sourceMaps: true, + envName: 'production', + }; + + /** @type {import('rollup').RollupOptions} */ const formatConfig = { input: ['src/index.ts'], - output: { - dir: moduleFormatToDirectory[format], - name, - format, - sourcemap: true, - globals: format === 'umd' ? getUMDGlobals() : {}, - validate: true, - interop: 'compat', // https://rollupjs.org/configuration-options/#output-interop - }, + output, plugins: [ nodePolyfills(), nodeExternals({ deps: true }), nodeResolve({ extensions }), - - babel({ - babelrc: false, - babelHelpers: 'bundled', - extensions, - configFile: babelConfigPath, - sourceMaps: true, - envName: 'production', - }), - + babel(babelOptions), svgr(), - - terser(), ], external, strictDeprecations: true, @@ -83,11 +92,32 @@ const createConfigForFormat = (format, overrides) => { return finalConfig; }; -const esmConfig = createConfigForFormat('esm'); -const umdConfig = createConfigForFormat('umd'); +const esmConfig = createConfigForFormat( + createOutput({ format: 'esm', useTerser: true }), +); +const umdConfig = createConfigForFormat( + createOutput({ format: 'umd', useTerser: true }), +); const defaultConfig = [esmConfig, umdConfig]; +// configurations for modern dev/prod bundle publishing +// to be used by packages that are included in the experiment +const modernDevProdConfig = createConfigForFormat([ + createOutput({ format: 'esm' }), + createOutput({ format: 'umd' }), + createOutput({ + format: 'esm', + useTerser: true, + outputNameSuffix: '-min', + }), + createOutput({ + format: 'umd', + useTerser: true, + outputNameSuffix: '-min', + }), +]); + // Add additional entry point to UMD build for test-utils if they exist doTestUtilsExist && defaultConfig.push( @@ -108,6 +138,8 @@ doTestUtilsExist && // FIXME: Figure out a way to get rid of this. // Creates a super-hacky `stories` bundle const storiesExist = glob.sync(storyGlob).length > 0; + +/** @type {import('rollup').RollupOptions} */ const storiesConfig = { ...esmConfig, input: glob.sync(storyGlob)[0], @@ -121,6 +153,6 @@ const storiesConfig = { storiesExist && defaultConfig.push(storiesConfig); -export { esmConfig, storiesConfig, umdConfig }; +export { modernDevProdConfig, esmConfig, storiesConfig, umdConfig }; export default defaultConfig; From e508329304992e777264d55c4018226f7ef70945 Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Mon, 24 Nov 2025 12:49:58 -0800 Subject: [PATCH 5/7] fix: type errors and missing command arg defs --- packages/icon/scripts/build/build-batch.ts | 19 +++++++++++++------ packages/icon/scripts/build/build.ts | 1 + tools/build/config/rollup.config.mjs | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/icon/scripts/build/build-batch.ts b/packages/icon/scripts/build/build-batch.ts index 03e9693582..eef3a3593e 100644 --- a/packages/icon/scripts/build/build-batch.ts +++ b/packages/icon/scripts/build/build-batch.ts @@ -1,11 +1,11 @@ /* eslint-disable no-console */ -import { MergedRollupOptions, rollup } from 'rollup'; +import { InputPluginOption, rollup, type RollupOptions } from 'rollup'; import { GENERATED_DIR } from './constants'; async function getBatchBuildOptions( batch: Array, -): Promise> { +): Promise> { const { constructUMDGlobalName } = await import( '@lg-tools/build/config/utils/constructUMDGlobalName.mjs' ); @@ -21,11 +21,11 @@ async function getBatchBuildOptions( { ...esmConfig, input: batch.map(icon => `${GENERATED_DIR}/${icon}.tsx`), - output: [esmConfig.output], + output: esmConfig.output, plugins: [ // Ensure @emotion packages are externalized (not bundled into icons) nodeExternals({ deps: true, include: [/@emotion/] }), - ...esmConfig.plugins, + ...(esmConfig.plugins as Array), ], }, // UMD builds need a single input file @@ -43,7 +43,7 @@ async function getBatchBuildOptions( plugins: [ // Ensure @emotion packages are externalized (not bundled into icons) nodeExternals({ deps: true, include: [/@emotion/] }), - ...umdConfig.plugins, + ...(umdConfig.plugins as Array), ], }; }), @@ -64,7 +64,14 @@ export async function buildBatch( for (const config of rollupConfigs) { const bundle = await rollup(config); - await Promise.all(config.output.map(bundle.write)); + if (config.output) { + const outputs = Array.isArray(config.output) + ? config.output + : [config.output]; + + await Promise.all(outputs.map(bundle.write)); + } + await bundle.close(); } } catch (e) { diff --git a/packages/icon/scripts/build/build.ts b/packages/icon/scripts/build/build.ts index ebf752b9c9..a258c1b266 100644 --- a/packages/icon/scripts/build/build.ts +++ b/packages/icon/scripts/build/build.ts @@ -89,6 +89,7 @@ async function buildIcons(options: BuildIconOptions): Promise { new Command() .description('Split icon files into batches for bundling in parallel') + .option('-f, --force', 'Force build all icons', false) .option('-v, --verbose', 'Enable verbose output', false) .action(buildIcons) .parse(); diff --git a/tools/build/config/rollup.config.mjs b/tools/build/config/rollup.config.mjs index 0eddd2eeff..85950f1072 100644 --- a/tools/build/config/rollup.config.mjs +++ b/tools/build/config/rollup.config.mjs @@ -54,7 +54,7 @@ const createOutput = ({ format, useTerser = false, outputNameSuffix = '' }) => { }; /** - * @param {import('rollup').OutputOptions} output + * @param {import('rollup').RollupOptions['output']} output * @param {Partial} [overrides] * @returns {import('rollup').RollupOptions} */ From d8cf9b9881d79e98be4c7660630efd3791dc6aef Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Mon, 24 Nov 2025 15:30:28 -0800 Subject: [PATCH 6/7] docs: update changelog of 'build' module --- .changeset/breezy-groups-turn.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.changeset/breezy-groups-turn.md b/.changeset/breezy-groups-turn.md index 1df714e510..fb9f5ae331 100644 --- a/.changeset/breezy-groups-turn.md +++ b/.changeset/breezy-groups-turn.md @@ -1,8 +1,9 @@ --- '@lg-tools/build': minor -'@lg-tools/cli': minor --- -Introduced new `lg build-minify` and `lg-build minify` commands to separately minify JavaScript bundle files. -Files to be minified can be specified using the `--glob` argument (default: `--glob=dist/**/*.*js --glob=!dist/**/*-min.*js`). -This allows generating both minified and non-minified bundles in the same package for use in different environments, decoupling minification from the main build process. \ No newline at end of file +Added a new exported `modernDevProdConfig` Rollup configuration, designed for component packages. + +This configuration generates both minified and non-minified bundles to support production and development environments respectively. Please update the `exports` field in your `package.json` to include a `browser.production` entry for both `import` and `require` that points to the minified bundle (`[bundle-name]-min.js`). This ensures that consumers’ build tools use the optimized, minified bundle in production automatically. + +The charts/legend package is the initial adopter of this configuration and is a good example of how to use this new configuration. \ No newline at end of file From 440ad95777a53112b38c39d6f0435ac0ca1fe72b Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Tue, 25 Nov 2025 11:48:46 -0800 Subject: [PATCH 7/7] fix: adjust testing bundle creation --- tools/build/config/rollup.config.mjs | 93 +++++++++++++++++----------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/tools/build/config/rollup.config.mjs b/tools/build/config/rollup.config.mjs index 85950f1072..8498d84639 100644 --- a/tools/build/config/rollup.config.mjs +++ b/tools/build/config/rollup.config.mjs @@ -14,7 +14,7 @@ import { getUMDGlobals } from './utils/getUMDGlobals.mjs'; import { defaultsDeep } from 'lodash-es'; const extensions = ['.ts', '.tsx']; -const testUtilsFilename = 'src/testing/index.ts'; +const testBundleGlob = 'src/testing/index.ts'; const storyGlob = 'src/*.stor{y,ies}.tsx'; const babelConfigPath = fileURLToPath( @@ -33,22 +33,27 @@ const moduleFormatToDirectory = { umd: 'dist/umd', }; -const doTestUtilsExist = glob.sync(testUtilsFilename).length > 0; - /** - * @param {{ format: import('rollup').OutputOptions['format'], useTerser?: boolean, outputNameSuffix?: string }} options + * @param {{ format: import('rollup').OutputOptions['format'], useTerser?: boolean, outputFile?: string, outputName?: string, outputDir?: string }} options * @returns {import('rollup').OutputOptions} */ -const createOutput = ({ format, useTerser = false, outputNameSuffix = '' }) => { +const createOutput = ({ + format, + useTerser = false, + outputFile = undefined, + outputName = '[name].js', + outputDir = moduleFormatToDirectory[format], +}) => { return { - dir: moduleFormatToDirectory[format], + dir: outputDir, + file: outputFile, name, format, sourcemap: true, globals: format === 'umd' ? getUMDGlobals() : {}, validate: true, interop: 'compat', // https://rollupjs.org/configuration-options/#output-interop - entryFileNames: `[name]${outputNameSuffix}.js`, + entryFileNames: outputName, plugins: useTerser ? [terser()] : [], }; }; @@ -92,6 +97,7 @@ const createConfigForFormat = (output, overrides = {}) => { return finalConfig; }; +// 1. Create the default esm/umd bundles configs const esmConfig = createConfigForFormat( createOutput({ format: 'esm', useTerser: true }), ); @@ -101,57 +107,74 @@ const umdConfig = createConfigForFormat( const defaultConfig = [esmConfig, umdConfig]; -// configurations for modern dev/prod bundle publishing -// to be used by packages that are included in the experiment +// 1.1. Create the modern dev/prod bundle configs const modernDevProdConfig = createConfigForFormat([ createOutput({ format: 'esm' }), createOutput({ format: 'umd' }), createOutput({ format: 'esm', useTerser: true, - outputNameSuffix: '-min', + outputName: '[name]-min.js', }), createOutput({ format: 'umd', useTerser: true, - outputNameSuffix: '-min', + outputName: '[name]-min.js', }), ]); -// Add additional entry point to UMD build for test-utils if they exist -doTestUtilsExist && +// 2. Create testing bundles (if applicable) +const testingBundleEntryPoints = glob.sync(testBundleGlob); + +if (testingBundleEntryPoints.length > 0) { defaultConfig.push( - createConfigForFormat('esm', { - input: testUtilsFilename, - output: { - dir: `${moduleFormatToDirectory['esm']}/testing`, + createConfigForFormat( + createOutput({ + format: 'esm', + useTerser: true, + outputDir: `${moduleFormatToDirectory['esm']}/testing`, + }), + { + input: testingBundleEntryPoints, }, - }), - createConfigForFormat('umd', { - input: testUtilsFilename, - output: { - dir: `${moduleFormatToDirectory['umd']}/testing`, + ), + createConfigForFormat( + createOutput({ + format: 'umd', + useTerser: true, + outputDir: `${moduleFormatToDirectory['umd']}/testing`, + }), + { + input: testingBundleEntryPoints, }, - }), + ), ); +} + +// 3. Create stories bundles (if applicable) + +const storiesEntryPoints = glob.sync(storyGlob); // FIXME: Figure out a way to get rid of this. // Creates a super-hacky `stories` bundle -const storiesExist = glob.sync(storyGlob).length > 0; - -/** @type {import('rollup').RollupOptions} */ -const storiesConfig = { - ...esmConfig, - input: glob.sync(storyGlob)[0], - output: { - format: 'esm', - file: 'stories.js', +const storiesConfig = createConfigForFormat( + { + ...createOutput({ + format: 'esm', + useTerser: true, + outputDir: null, + outputFile: 'stories.js', + }), sourcemap: false, - globals: esmConfig.output.globals, }, -}; + { + input: storiesEntryPoints[0], + }, +); -storiesExist && defaultConfig.push(storiesConfig); +if (storiesEntryPoints.length > 0) { + defaultConfig.push(storiesConfig); +} export { modernDevProdConfig, esmConfig, storiesConfig, umdConfig };