From 1dd59a5e0a57ec5234a5d96a94121cd5cd2bc5fd Mon Sep 17 00:00:00 2001 From: Alice Pote Date: Wed, 8 Nov 2023 21:16:17 -0500 Subject: [PATCH] chore(esbuild): build sys-node bundle with esbuild (#5010) This adds a new esbuild-based bundle for the sys-node bundle, which includes the `CompilerSystem` implementation for node.js (currently our only full implementation). --- scripts/esbuild/build.ts | 3 +- scripts/esbuild/cli.ts | 5 ++- scripts/esbuild/sys-node.ts | 78 +++++++++++++++++++++++++++++++++++++ scripts/esbuild/util.ts | 17 ++------ src/sys/node/worker.ts | 4 +- 5 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 scripts/esbuild/sys-node.ts diff --git a/scripts/esbuild/build.ts b/scripts/esbuild/build.ts index 0ad9179ed27..63f4e5e5670 100644 --- a/scripts/esbuild/build.ts +++ b/scripts/esbuild/build.ts @@ -1,5 +1,6 @@ import { getOptions } from '../utils/options'; import { buildCli } from './cli'; +import { buildSysNode } from './sys-node'; // the main entry point for the Esbuild-based build async function main() { @@ -9,7 +10,7 @@ async function main() { isWatch: !!process.argv.includes('--watch'), }); - await buildCli(opts); + await Promise.all([buildCli(opts), buildSysNode(opts)]); } main(); diff --git a/scripts/esbuild/cli.ts b/scripts/esbuild/cli.ts index f98d6f838af..6e8755a406c 100644 --- a/scripts/esbuild/cli.ts +++ b/scripts/esbuild/cli.ts @@ -50,9 +50,10 @@ export async function buildCli(opts: BuildOptions) { }; // CommonJS build options - const cjsContext: ESBuildOptions = { + const cjsOptions: ESBuildOptions = { ...cliEsbuildOptions, outfile: join(outputDir, cjsFilename), + platform: 'node', format: 'cjs', banner: { js: getBanner(opts, `Stencil CLI (CommonJS)`, true), @@ -78,5 +79,5 @@ export async function buildCli(opts: BuildOptions) { types: dtsFilename, }); - return runBuilds([esmOptions, cjsContext], opts); + return runBuilds([esmOptions, cjsOptions], opts); } diff --git a/scripts/esbuild/sys-node.ts b/scripts/esbuild/sys-node.ts new file mode 100644 index 00000000000..8583897d4c1 --- /dev/null +++ b/scripts/esbuild/sys-node.ts @@ -0,0 +1,78 @@ +import type { BuildOptions as ESBuildOptions } from 'esbuild'; +import fs from 'fs-extra'; +import { join } from 'path'; + +import { sysNodeExternalBundles } from '../bundles/sys-node'; +import { getBanner } from '../utils/banner'; +import type { BuildOptions } from '../utils/options'; +import { writePkgJson } from '../utils/write-pkg-json'; +import { getBaseEsbuildOptions, getEsbuildAliases, getEsbuildExternalModules, runBuilds } from './util'; + +export async function buildSysNode(opts: BuildOptions) { + const inputDir = join(opts.buildDir, 'sys', 'node'); + const srcDir = join(opts.srcDir, 'sys', 'node'); + const inputFile = join(srcDir, 'index.ts'); + const outputFile = join(opts.output.sysNodeDir, 'index.js'); + + // clear out rollup stuff and ensure directory exists + await fs.emptyDir(opts.output.sysNodeDir); + + // create public d.ts + let dts = await fs.readFile(join(inputDir, 'public.d.ts'), 'utf8'); + dts = dts.replace('@stencil/core/internal', '../../internal/index'); + await fs.writeFile(join(opts.output.sysNodeDir, 'index.d.ts'), dts); + + // write @stencil/core/sys/node/package.json + writePkgJson(opts, opts.output.sysNodeDir, { + name: '@stencil/core/sys/node', + description: 'Stencil Node System.', + main: 'index.js', + types: 'index.d.ts', + }); + + const external = [ + ...getEsbuildExternalModules(opts, opts.output.sysNodeDir), + // normally you wouldn't externalize your "own" directory here, but since + // we build multiple things within `opts.output.sysNodeDir` which should + // externalize each other we need to do so + join(opts.output.sysNodeDir, '*'), + ]; + + const sysNodeAliases = getEsbuildAliases(); + + const sysNodeOptions: ESBuildOptions = { + ...getBaseEsbuildOptions(), + entryPoints: [inputFile], + bundle: true, + format: 'cjs', + outfile: outputFile, + platform: 'node', + logLevel: 'info', + external, + minify: true, + alias: sysNodeAliases, + banner: { js: getBanner(opts, `Stencil Node System`, true) }, + }; + + // sys/node/worker.js bundle + const inputWorkerFile = join(srcDir, 'worker.ts'); + const outputWorkerFile = join(opts.output.sysNodeDir, 'worker.js'); + + const workerOptions: ESBuildOptions = { + ...getBaseEsbuildOptions(), + entryPoints: [inputWorkerFile], + bundle: true, + format: 'cjs', + outfile: outputWorkerFile, + platform: 'node', + logLevel: 'info', + external, + minify: true, + alias: sysNodeAliases, + banner: { js: getBanner(opts, `Stencil Node System Worker`, true) }, + }; + + await sysNodeExternalBundles(opts); + + return runBuilds([sysNodeOptions, workerOptions], opts); +} diff --git a/scripts/esbuild/util.ts b/scripts/esbuild/util.ts index d721e62abc5..4d1ca15516b 100644 --- a/scripts/esbuild/util.ts +++ b/scripts/esbuild/util.ts @@ -21,6 +21,7 @@ export function getEsbuildAliases(): Record { '@stencil/core/dev-server': './dev-server/index.js', '@stencil/core/mock-doc': './mock-doc/index.cjs', '@stencil/core/internal/testing': './internal/testing/index.js', + '@sys-api-node': './sys/node/index.js', // mapping node.js module names to `sys/node` "cache" // @@ -28,6 +29,8 @@ export function getEsbuildAliases(): Record { // of the Stencil distributable but also have our separate bundles // reference the same file prompts: './sys/node/prompts.js', + glob: './sys/node/glob.js', + 'graceful-fs': './sys/node/graceful-fs.js', }; } @@ -43,31 +46,17 @@ const externalNodeModules = [ '@jest/core', '@jest/reporters', '@microsoft/typescript-etw', - 'assert', - 'buffer', - 'child_process', - 'console', - 'constants', 'expect', 'fsevents', - 'inspector', 'jest', 'jest-cli', 'jest-config', 'jest-message-id', 'jest-pnp-resolver', 'jest-runner', - 'net', 'puppeteer', 'puppeteer-core', - 'readline', - 'stream', - 'tty', - 'url', - 'util', - 'vm', 'yargs', - 'zlib', ]; /** diff --git a/src/sys/node/worker.ts b/src/sys/node/worker.ts index 7e8a39a7adb..75674e83cd4 100644 --- a/src/sys/node/worker.ts +++ b/src/sys/node/worker.ts @@ -1,10 +1,8 @@ -import '@stencil/core/compiler'; - +import * as coreCompiler from '@stencil/core/compiler'; import * as nodeApi from '@sys-api-node'; import { initNodeWorkerThread } from './node-worker-thread'; -const coreCompiler = (global as any).stencil as typeof import('@stencil/core/compiler'); const nodeSys = nodeApi.createNodeSys({ process: process }); const msgHandler = coreCompiler.createWorkerMessageHandler(nodeSys);