Skip to content

Commit 3c41584

Browse files
Add an option to bundle NPM packages while installing
1 parent d07269a commit 3c41584

File tree

6 files changed

+496
-45
lines changed

6 files changed

+496
-45
lines changed

npm/private/lifecycle/lifecycle-hooks.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ const path = require('path')
55
const { safeReadPackageJsonFromDir } = require('@pnpm/read-package-json')
66
const { runLifecycleHook } = require('@pnpm/lifecycle')
77

8+
//const esbuild = require('esbuild-wasm');
9+
const {rollup} = require('rollup');
10+
const {dts} = require('rollup-plugin-dts');
11+
const commonjs = require('@rollup/plugin-commonjs');
12+
const json = require('@rollup/plugin-json');
13+
const { nodeResolve } = require('@rollup/plugin-node-resolve');
14+
815
async function mkdirp(p) {
916
if (p && !fs.existsSync(p)) {
1017
await mkdirp(path.dirname(p))
@@ -128,6 +135,88 @@ function isWindows() {
128135
return os.platform() === 'win32'
129136
}
130137

138+
139+
async function optimizePackage(destDir) {
140+
// We first copy the package to a temporary directory so that we don't have `node_modules`
141+
// in our name. Otherwise, `dts` will refuse to do anthing, since `respectExternals` defaults to false.
142+
// Setting that to true will inline _all_ externals (including dependencies), which
143+
// can break typechecking. Better to bundle the dependencies on their own.
144+
const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'aspect_rules_js_'));
145+
await fs.promises.cp(destDir, tempDir, {recursive: true, force: true});
146+
147+
const packageJsonText = await fs.promises.readFile(path.join(tempDir, 'package.json'));
148+
const packageJson = JSON.parse(packageJsonText);
149+
150+
const typesMain = path.join(tempDir, packageJson.types);
151+
const cjsMain = path.join(tempDir, packageJson.main);
152+
const esmMain = path.join(tempDir, packageJson.module);
153+
154+
async function bundleDts(input) {
155+
const result = await rollup({
156+
input,
157+
plugins: [dts()],
158+
});
159+
await result.write({
160+
file: input,
161+
format: 'esm',
162+
});
163+
}
164+
165+
async function bundle(input, format, plugins) {
166+
const result = await rollup({
167+
input,
168+
output: {
169+
file: input,
170+
format,
171+
},
172+
plugins,
173+
});
174+
await result.write({
175+
file: input,
176+
format,
177+
});
178+
}
179+
180+
const bundlePromises = [];
181+
typesMain && bundlePromises.push(bundleDts(typesMain));
182+
cjsMain && bundlePromises.push(bundle(cjsMain, 'cjs', [commonjs(), json()]));
183+
esmMain && bundlePromises.push(bundle(esmMain, 'esm', [nodeResolve(), json()]));
184+
185+
// Would be faster to use esbuild, but we cannot bundle esbuild itself :/
186+
/*cjsMain && bundlePromises.push(esbuild.build({
187+
entryPoints: [cjsMain],
188+
bundle: true,
189+
outfile: cjsMain,
190+
platform: 'node',
191+
format: 'cjs',
192+
}));
193+
esmMain && bundlePromises.push(esbuild.build({
194+
entryPoints: [esmMain],
195+
bundle: true,
196+
outfile: esmMain,
197+
platform: 'node',
198+
format: 'esm',
199+
}));*/
200+
201+
await Promise.all(bundlePromises);
202+
203+
await fs.promises.rm(destDir, {recursive: true, force: true});
204+
205+
async function rename(tmpPath, realPath) {
206+
const realDir = path.dirname(realPath);
207+
await fs.promises.mkdir(realDir, {recursive: true});
208+
await fs.promises.cp(tmpPath, realPath);
209+
}
210+
211+
const emitPromises = [];
212+
typesMain && emitPromises.push(rename(typesMain, path.join(destDir, packageJson.types)));
213+
cjsMain && emitPromises.push(rename(cjsMain, path.join(destDir, packageJson.main)));
214+
esmMain && emitPromises.push(rename(esmMain, path.join(destDir, packageJson.module)));
215+
await Promise.all(emitPromises);
216+
217+
await fs.promises.writeFile(path.join(destDir, 'package.json'), packageJsonText);
218+
}
219+
131220
async function main(args) {
132221
if (args.length < 3) {
133222
console.error(
@@ -260,6 +349,10 @@ async function main(args) {
260349
// Run user specified custom postinstall hook
261350
await runLifecycleHook('custom_postinstall', rulesJsJson, opts)
262351
}
352+
353+
if (rulesJsJson.optimize_package) {
354+
await optimizePackage(outputDir);
355+
}
263356
}
264357

265358
// Copy contents of a package dir to a destination dir (without copying the package dir itself)

npm/private/lifecycle/min/index.min.js

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

0 commit comments

Comments
 (0)