diff --git a/src/compiler/build/build-ctx.ts b/src/compiler/build/build-ctx.ts index 9da4d95b95f..0567480da71 100644 --- a/src/compiler/build/build-ctx.ts +++ b/src/compiler/build/build-ctx.ts @@ -45,6 +45,7 @@ export class BuildContext implements d.BuildCtx { indexBuildCount = 0; indexDoc: Document = undefined; isRebuild = false; + isExternal: (id: string, importer: string, isResolved: boolean) => boolean; moduleFiles: d.Module[] = []; outputs: d.BuildOutput[] = []; packageJson: d.PackageJsonData = {}; @@ -68,6 +69,7 @@ export class BuildContext implements d.BuildCtx { this.buildId = ++this.compilerCtx.activeBuildId; this.debug = config.logger.debug.bind(config.logger); + this.isExternal = getIdMatcher(config.rollupConfig?.inputOptions?.external); } start() { @@ -215,6 +217,46 @@ export const getBuildTimestamp = () => { return timestamp; }; +export function ensureArray(items: (T | false | null | undefined)[] | T | false | null | undefined): T[] { + if (Array.isArray(items)) { + return items.filter(Boolean) as T[]; + } + if (items) { + return [items]; + } + return []; +} + +const getIdMatcher = >( + option: + | undefined + | boolean + | string + | RegExp + | (string | RegExp)[] + | ((id: string, ...parameters: T) => boolean | null | void) +): ((id: string, ...parameters: T) => boolean) => { + if (option === true) { + return () => true; + } + if (typeof option === 'function') { + return (id, ...parameters) => (!id.startsWith('\0') && option(id, ...parameters)) || false; + } + if (option) { + const ids = new Set(); + const matchers: RegExp[] = []; + for (const value of ensureArray(option)) { + if (value instanceof RegExp) { + matchers.push(value); + } else { + ids.add(value); + } + } + return (id: string, ..._arguments) => ids.has(id) || matchers.some((matcher) => matcher.test(id)); + } + return () => false; +}; + const getProgress = (completedTasks: d.BuildTask[]) => { let progressIndex = 0; const taskKeys = Object.keys(ProgressTask); diff --git a/src/compiler/bundle/bundle-output.ts b/src/compiler/bundle/bundle-output.ts index 85b2d08e556..423e3e211e2 100644 --- a/src/compiler/bundle/bundle-output.ts +++ b/src/compiler/bundle/bundle-output.ts @@ -135,6 +135,8 @@ export const getRollupOptions = ( onwarn: createOnWarnFn(buildCtx.diagnostics), cache: compilerCtx.rollupCache.get(bundleOpts.id), + + external: config.rollupConfig?.inputOptions?.external, }; return rollupOptions; diff --git a/src/compiler/config/test/validate-rollup-config.spec.ts b/src/compiler/config/test/validate-rollup-config.spec.ts index 3040a929f01..1064d2aa4ed 100644 --- a/src/compiler/config/test/validate-rollup-config.spec.ts +++ b/src/compiler/config/test/validate-rollup-config.spec.ts @@ -62,6 +62,7 @@ describe('validateStats', () => { config.rollupConfig = { inputOptions: { context: 'window', + external: 'external_symbol', notAnOption: {}, }, outputOptions: { @@ -76,6 +77,7 @@ describe('validateStats', () => { rollupConfig: { inputOptions: { context: 'window', + external: 'external_symbol', }, outputOptions: { globals: { diff --git a/src/compiler/config/validate-rollup-config.ts b/src/compiler/config/validate-rollup-config.ts index e0ac9ab361d..96102dc90d2 100644 --- a/src/compiler/config/validate-rollup-config.ts +++ b/src/compiler/config/validate-rollup-config.ts @@ -17,7 +17,7 @@ const getCleanRollupConfig = (rollupConfig: d.RollupConfig): d.RollupConfig => { if (rollupConfig.inputOptions && isObject(rollupConfig.inputOptions)) { cleanRollupConfig = { ...cleanRollupConfig, - inputOptions: pluck(rollupConfig.inputOptions, ['context', 'moduleContext', 'treeshake']), + inputOptions: pluck(rollupConfig.inputOptions, ['context', 'moduleContext', 'treeshake', 'external']), }; } diff --git a/src/compiler/transformers/collections/parse-collection-manifest.ts b/src/compiler/transformers/collections/parse-collection-manifest.ts index 0e902227d4c..7de8ae968d1 100644 --- a/src/compiler/transformers/collections/parse-collection-manifest.ts +++ b/src/compiler/transformers/collections/parse-collection-manifest.ts @@ -16,6 +16,8 @@ export const parseCollectionManifest = ( const compilerVersion: d.CollectionCompilerVersion = collectionManifest.compiler || ({} as any); + const isExternal = buildCtx.isExternal(collectionName, 'collection', true); + const collection: d.CollectionCompilerMeta = { collectionName: collectionName, moduleId: collectionName, @@ -27,10 +29,13 @@ export const parseCollectionManifest = ( typescriptVersion: compilerVersion.typescriptVersion || '', }, bundles: parseBundles(collectionManifest), + isExternal, }; - parseGlobal(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection); - parseCollectionComponents(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection); + if (!isExternal) { + parseGlobal(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection); + parseCollectionComponents(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection); + } return collection; }; diff --git a/src/declarations/stencil-private.ts b/src/declarations/stencil-private.ts index e80ac8c6401..bce0166fd1c 100644 --- a/src/declarations/stencil-private.ts +++ b/src/declarations/stencil-private.ts @@ -253,6 +253,7 @@ export interface BuildCtx { indexBuildCount: number; indexDoc: Document; isRebuild: boolean; + isExternal: (id: string, importer: string, isResolved: boolean) => boolean; moduleFiles: Module[]; packageJson: PackageJsonData; pendingCopyTasks: Promise[]; @@ -474,6 +475,7 @@ export interface CollectionCompilerMeta { bundles?: { components: string[]; }[]; + isExternal?: boolean; } export interface CollectionCompilerVersion { diff --git a/src/declarations/stencil-public-compiler.ts b/src/declarations/stencil-public-compiler.ts index 28bb1e78dc6..4499a2e7997 100644 --- a/src/declarations/stencil-public-compiler.ts +++ b/src/declarations/stencil-public-compiler.ts @@ -1494,6 +1494,11 @@ export interface RollupInputOptions { context?: string; moduleContext?: ((id: string) => string) | { [id: string]: string }; treeshake?: boolean; + external?: + | (string | RegExp)[] + | string + | RegExp + | ((source: string, importer: string | undefined, isResolved: boolean) => boolean | null | undefined); } export interface RollupOutputOptions {