Skip to content

Commit 3278d9b

Browse files
Add an option to bundle NPM packages while installing
1 parent d07269a commit 3278d9b

6 files changed

Lines changed: 493 additions & 45 deletions

File tree

npm/private/lifecycle/lifecycle-hooks.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ 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+
814
async function mkdirp(p) {
915
if (p && !fs.existsSync(p)) {
1016
await mkdirp(path.dirname(p))
@@ -128,6 +134,88 @@ function isWindows() {
128134
return os.platform() === 'win32'
129135
}
130136

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

265357
// 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)