-
Notifications
You must be signed in to change notification settings - Fork 792
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(esbuild): build the internal module with esbuild (#5276)
This adds the ability to build the modules within `internal/` with Esbuild, replicating the existing Rollup build. STENCIL-990
- Loading branch information
1 parent
5c54f38
commit b09f233
Showing
17 changed files
with
462 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import type { BuildOptions as ESBuildOptions } from 'esbuild'; | ||
import fs from 'fs-extra'; | ||
import { join } from 'path'; | ||
|
||
import { BuildOptions } from '../utils/options'; | ||
import { writePkgJson } from '../utils/write-pkg-json'; | ||
import { getBaseEsbuildOptions } from './util'; | ||
|
||
/** | ||
* Get an object containing ESbuild options to build the internal app data | ||
* file. This function also performs relevant side-effects, like writing a | ||
* `package.json` file to disk. | ||
* | ||
* @param opts build options | ||
* @returns a Promise wrapping an array of ESbuild option objects | ||
*/ | ||
export async function getInternalAppDataBundles(opts: BuildOptions): Promise<ESBuildOptions[]> { | ||
const appDataBuildDir = join(opts.buildDir, 'app-data'); | ||
const appDataSrcDir = join(opts.srcDir, 'app-data'); | ||
const outputInternalAppDataDir = join(opts.output.internalDir, 'app-data'); | ||
|
||
await fs.emptyDir(outputInternalAppDataDir); | ||
|
||
// copy @stencil/core/internal/app-data/index.d.ts | ||
await fs.copyFile(join(appDataBuildDir, 'index.d.ts'), join(outputInternalAppDataDir, 'index.d.ts')); | ||
|
||
// write @stencil/core/internal/app-data/package.json | ||
writePkgJson(opts, outputInternalAppDataDir, { | ||
name: '@stencil/core/internal/app-data', | ||
description: 'Used for default app data and build conditionals within builds.', | ||
main: 'index.cjs', | ||
module: 'index.js', | ||
types: 'index.d.ts', | ||
sideEffects: false, | ||
}); | ||
|
||
const appDataBaseOptions: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [join(appDataSrcDir, 'index.ts')], | ||
platform: 'node', | ||
}; | ||
|
||
const appDataESM: ESBuildOptions = { | ||
...appDataBaseOptions, | ||
format: 'esm', | ||
outfile: join(outputInternalAppDataDir, 'index.js'), | ||
}; | ||
|
||
const appDataCJS: ESBuildOptions = { | ||
...appDataBaseOptions, | ||
format: 'cjs', | ||
outfile: join(outputInternalAppDataDir, 'index.cjs'), | ||
}; | ||
|
||
return [appDataESM, appDataCJS]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import type { BuildOptions as ESBuildOptions } from 'esbuild'; | ||
import { replace } from 'esbuild-plugin-replace'; | ||
import fs from 'fs-extra'; | ||
import glob from 'glob'; | ||
import { join } from 'path'; | ||
|
||
import { getBanner } from '../utils/banner'; | ||
import { BuildOptions, createReplaceData } from '../utils/options'; | ||
import { writePkgJson } from '../utils/write-pkg-json'; | ||
import { externalAlias, getBaseEsbuildOptions, getEsbuildAliases, getEsbuildExternalModules } from './util'; | ||
|
||
/** | ||
* Create objects containing ESbuild options for the two bundles which need to | ||
* be written to `internal/client`. This also performs relevant side-effects, | ||
* like clearing out the directory and writing a `package.json` script to disk. | ||
* | ||
* @param opts build options | ||
* @returns an array of ESBuild option objects | ||
*/ | ||
export async function getInternalClientBundle(opts: BuildOptions): Promise<ESBuildOptions[]> { | ||
const inputClientDir = join(opts.srcDir, 'client'); | ||
const outputInternalClientDir = join(opts.output.internalDir, 'client'); | ||
const outputInternalClientPolyfillsDir = join(outputInternalClientDir, 'polyfills'); | ||
|
||
await fs.emptyDir(outputInternalClientDir); | ||
await fs.emptyDir(outputInternalClientPolyfillsDir); | ||
|
||
await copyPolyfills(opts, outputInternalClientPolyfillsDir); | ||
|
||
// write @stencil/core/internal/client/package.json | ||
writePkgJson(opts, outputInternalClientDir, { | ||
name: '@stencil/core/internal/client', | ||
description: | ||
'Stencil internal client platform to be imported by the Stencil Compiler and internal runtime. Breaking changes can and will happen at any time.', | ||
main: 'index.js', | ||
sideEffects: false, | ||
}); | ||
|
||
const internalClientAliases = getEsbuildAliases(); | ||
internalClientAliases['@platform'] = join(inputClientDir, 'index.ts'); | ||
|
||
const clientExternal = getEsbuildExternalModules(opts, opts.output.internalDir); | ||
|
||
const internalClientBundle: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [join(inputClientDir, 'index.ts')], | ||
format: 'esm', | ||
outfile: join(outputInternalClientDir, 'index.js'), | ||
platform: 'node', | ||
external: clientExternal, | ||
alias: internalClientAliases, | ||
banner: { | ||
js: getBanner(opts, 'Stencil Client Platform'), | ||
}, | ||
plugins: [ | ||
replace(createReplaceData(opts)), | ||
externalAlias('@app-data', '@stencil/core/internal/app-data'), | ||
externalAlias('@utils/shadow-css', './shadow-css.js'), | ||
// we want to get the esm, not the cjs, since we're creating an esm | ||
// bundle here | ||
externalAlias('@stencil/core/mock-doc', '../../mock-doc/index.js'), | ||
], | ||
}; | ||
|
||
const patchBrowserAliases = getEsbuildAliases(); | ||
|
||
const polyfills = await fs.readdir(join(opts.srcDir, 'client', 'polyfills')); | ||
for (const polyFillFile of polyfills) { | ||
patchBrowserAliases[join('./polyfills', polyFillFile)] = join(opts.srcDir, 'client', 'polyfills'); | ||
} | ||
|
||
const patchBrowserExternal = [ | ||
...getEsbuildExternalModules(opts, opts.output.internalDir), | ||
'@stencil/core', | ||
'@stencil/core/mock-doc', | ||
]; | ||
|
||
const internalClientPatchBrowserBundle: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [join(inputClientDir, 'client-patch-browser.ts')], | ||
format: 'esm', | ||
outfile: join(outputInternalClientDir, 'patch-browser.js'), | ||
platform: 'node', | ||
external: patchBrowserExternal, | ||
alias: patchBrowserAliases, | ||
banner: { | ||
js: getBanner(opts, 'Stencil Client Patch Browser'), | ||
}, | ||
plugins: [ | ||
replace(createReplaceData(opts)), | ||
externalAlias('@platform', '@stencil/core'), | ||
externalAlias('@app-data', '@stencil/core/internal/app-data'), | ||
], | ||
}; | ||
|
||
return [internalClientBundle, internalClientPatchBrowserBundle]; | ||
} | ||
|
||
async function copyPolyfills(opts: BuildOptions, outputInternalClientPolyfillsDir: string) { | ||
const srcPolyfillsDir = join(opts.srcDir, 'client', 'polyfills'); | ||
|
||
const srcPolyfillFiles = glob.sync('*.js', { cwd: srcPolyfillsDir }); | ||
|
||
await Promise.all( | ||
srcPolyfillFiles.map(async (fileName) => { | ||
const src = join(srcPolyfillsDir, fileName); | ||
const dest = join(outputInternalClientPolyfillsDir, fileName); | ||
await fs.copyFile(src, dest); | ||
}), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import type { BuildOptions as ESBuildOptions } from 'esbuild'; | ||
import fs from 'fs-extra'; | ||
import { join } from 'path'; | ||
|
||
import { getBanner } from '../utils/banner'; | ||
import { bundleDts } from '../utils/bundle-dts'; | ||
import { BuildOptions } from '../utils/options'; | ||
import { writePkgJson } from '../utils/write-pkg-json'; | ||
import { externalAlias, getBaseEsbuildOptions, getEsbuildAliases, getEsbuildExternalModules } from './util'; | ||
|
||
/** | ||
* Create objects containing ESbuild options for the two bundles comprising | ||
* the hydrate platform. This also performs relevant side-effects, like | ||
* clearing out a directory and writing a `package.json` script to disk. | ||
* | ||
* @param opts build options | ||
* @returns an array of ESBuild option objects | ||
*/ | ||
export async function getInternalPlatformHydrateBundles(opts: BuildOptions): Promise<ESBuildOptions[]> { | ||
const inputHydrateDir = join(opts.buildDir, 'hydrate'); | ||
const hydrateSrcDir = join(opts.srcDir, 'hydrate'); | ||
const outputInternalHydrateDir = join(opts.output.internalDir, 'hydrate'); | ||
|
||
await fs.emptyDir(outputInternalHydrateDir); | ||
|
||
// write @stencil/core/internal/hydrate/package.json | ||
writePkgJson(opts, outputInternalHydrateDir, { | ||
name: '@stencil/core/internal/hydrate', | ||
description: | ||
'Stencil internal hydrate platform to be imported by the Stencil Compiler. Breaking changes can and will happen at any time.', | ||
main: 'index.js', | ||
}); | ||
|
||
await createHydrateRunnerDtsBundle(opts, inputHydrateDir, outputInternalHydrateDir); | ||
|
||
const hydratePlatformInput = join(hydrateSrcDir, 'platform', 'index.js'); | ||
|
||
const external = [...getEsbuildExternalModules(opts, outputInternalHydrateDir), '@stencil/core/mock-doc']; | ||
|
||
const internalHydrateAliases = getEsbuildAliases(); | ||
internalHydrateAliases['@platform'] = hydratePlatformInput; | ||
|
||
const internalHydratePlatformBundle: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [hydratePlatformInput], | ||
format: 'esm', | ||
platform: 'node', | ||
outfile: join(outputInternalHydrateDir, 'index.js'), | ||
external, | ||
alias: internalHydrateAliases, | ||
banner: { | ||
js: getBanner(opts, 'Stencil Hydrate Platform'), | ||
}, | ||
plugins: [ | ||
externalAlias('@utils/shadow-css', '../client/shadow-css.js'), | ||
externalAlias('@app-data', '@stencil/core/internal/app-data'), | ||
// this needs to be externalized and also pointed at the esm version | ||
externalAlias('@stencil/core/mock-doc', '../../mock-doc/index.js'), | ||
], | ||
}; | ||
|
||
const internalHydrateRunnerBundle: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [join(hydrateSrcDir, 'runner', 'index.js')], | ||
external, | ||
format: 'esm', | ||
platform: 'node', | ||
outfile: join(outputInternalHydrateDir, 'runner.js'), | ||
banner: { | ||
js: getBanner(opts, 'Stencil Hydrate Runner'), | ||
}, | ||
plugins: [ | ||
externalAlias('@utils/shadow-css', '../client/shadow-css.js'), | ||
externalAlias('@app-data', '@stencil/core/internal/app-data'), | ||
externalAlias('@hydrate-factory', '@stencil/core/hydrate-factory'), | ||
], | ||
}; | ||
|
||
return [internalHydratePlatformBundle, internalHydrateRunnerBundle]; | ||
} | ||
|
||
async function createHydrateRunnerDtsBundle(opts: BuildOptions, inputHydrateDir: string, outputDir: string) { | ||
// bundle @stencil/core/internal/hydrate/runner.d.ts | ||
const dtsEntry = join(inputHydrateDir, 'runner', 'index.d.ts'); | ||
const dtsContent = await bundleDts(opts, dtsEntry); | ||
|
||
const outputPath = join(outputDir, 'runner.d.ts'); | ||
await fs.writeFile(outputPath, dtsContent); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import type { BuildOptions as ESBuildOptions } from 'esbuild'; | ||
import fs from 'fs-extra'; | ||
import { join } from 'path'; | ||
|
||
import { BuildOptions } from '../utils/options'; | ||
import { writePkgJson } from '../utils/write-pkg-json'; | ||
import { externalAlias, getBaseEsbuildOptions, getEsbuildAliases, getEsbuildExternalModules } from './util'; | ||
|
||
/** | ||
* Get an ESBuild configuration object for the internal testing bundle. This | ||
* function also has side-effects which set things up for the bundle to be built | ||
* correctly, like writing a `package.json` file to disk. | ||
* | ||
* @param opts build options | ||
* @returns a promise wrapping an object holding options for ESBuild | ||
*/ | ||
export async function getInternalTestingBundle(opts: BuildOptions): Promise<ESBuildOptions> { | ||
const inputTestingPlatform = join(opts.srcDir, 'testing', 'platform', 'index.ts'); | ||
const outputTestingPlatformDir = join(opts.output.internalDir, 'testing'); | ||
|
||
await fs.emptyDir(outputTestingPlatformDir); | ||
|
||
// write @stencil/core/internal/testing/package.json | ||
writePkgJson(opts, outputTestingPlatformDir, { | ||
name: '@stencil/core/internal/testing', | ||
description: | ||
'Stencil internal testing platform to be imported by the Stencil Compiler. Breaking changes can and will happen at any time.', | ||
main: 'index.js', | ||
}); | ||
|
||
const internalTestingAliases = { | ||
...getEsbuildAliases(), | ||
'@platform': inputTestingPlatform, | ||
}; | ||
|
||
const external = [...getEsbuildExternalModules(opts, opts.output.internalDir), '@stencil/core/mock-doc']; | ||
|
||
const internalTestingBuildOptions: ESBuildOptions = { | ||
...getBaseEsbuildOptions(), | ||
entryPoints: [inputTestingPlatform], | ||
bundle: true, | ||
format: 'cjs', | ||
outfile: join(outputTestingPlatformDir, 'index.js'), | ||
platform: 'node', | ||
logLevel: 'info', | ||
external, | ||
alias: internalTestingAliases, | ||
plugins: [ | ||
externalAlias('@app-data', '@stencil/core/internal/app-data'), | ||
externalAlias('@utils/shadow-css', '../client/shadow-css.js'), | ||
], | ||
}; | ||
return internalTestingBuildOptions; | ||
} |
Oops, something went wrong.