diff --git a/docs/05-plugins.md b/docs/05-plugins.md index a0e89a842e6..4049760b826 100644 --- a/docs/05-plugins.md +++ b/docs/05-plugins.md @@ -19,9 +19,9 @@ The following plugin will intercept any imports of `virtual-module` without acce export default function myExample () { return { name: 'my-example', // this name will show up in warnings and errors - resolveId ( importee ) { - if (importee === 'virtual-module') { - return importee; // this signals that rollup should not ask other plugins or check the file system to find this id + resolveId ( source ) { + if (source === 'virtual-module') { + return source; // this signals that rollup should not ask other plugins or check the file system to find this id } return null; // other ids should be handled as usually }, @@ -182,10 +182,19 @@ Kind: `async, parallel` Called initially each time `bundle.generate()` or `bundle.write()` is called. To get notified when generation has completed, use the `generateBundle` and `renderError` hooks. #### `resolveDynamicImport` -Type: `(specifier: string | ESTree.Node, importer: string) => string | false | null`
+Type: `(specifier: string | ESTree.Node, importer: string) => string | false | null | {id: string, external?: boolean}`
Kind: `async, first` -Defines a custom resolver for dynamic imports. In case a dynamic import is not passed a string as argument, this hook gets access to the raw AST nodes to analyze. Returning `null` will defer to other resolvers and eventually to `resolveId` if this is possible; returning `false` signals that the import should be kept as it is and not be passed to other resolvers thus making it external. Note that the return value of this hook will not be passed to `resolveId` afterwards; if you need access to the static resolution algorithm, you can use `this.resolveId(importee, importer)` on the plugin context. +Defines a custom resolver for dynamic imports. Returning `false` signals that the import should be kept as it is and not be passed to other resolvers thus making it external. Similar to the [`resolveId`](guide/en#resolveid) hook, you can also return an object to resolve the import to a different id while marking it as external at the same time. + +In case a dynamic import is passed a string as argument, a string returned from this hook will be interpreted as an existing module id while returning `null` will defer to other resolvers and eventually to `resolveId` . + +In case a dynamic import is not passed a string as argument, this hook gets access to the raw AST nodes to analyze and behaves slightly different in the following ways: +- If all plugins return `null`, the import is treated as `external` without a warning. +- If a string is returned, this string is *not* interpreted as a module id but is instead used as a replacement for the import argument. It is the responsibility of the plugin to make sure the generated code is valid. +- To resolve such an import to an existing module, you can still return an object `{id, external}`. + +Note that the return value of this hook will not be passed to `resolveId` afterwards; if you need access to the static resolution algorithm, you can use [`this.resolve(source, importer)`](guide/en#this-resolve-source-string-importer-string-promise-id-string-external-boolean-null) on the plugin context. #### `resolveFileUrl` Type: `({assetReferenceId: string | null, chunkId: string, chunkReferenceId: string | null, fileName: string, format: string, moduleId: string, relativePath: string}) => string | null`
@@ -215,17 +224,17 @@ resolveFileUrl({fileName}) { ``` #### `resolveId` -Type: `(importee: string, importer: string) => string | false | null | {id: string, external?: boolean}`
+Type: `(source: string, importer: string) => string | false | null | {id: string, external?: boolean}`
Kind: `async, first` -Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Returning `null` defers to other `resolveId` functions (and eventually the default resolution behavior); returning `false` signals that `importee` should be treated as an external module and not included in the bundle. +Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Returning `null` defers to other `resolveId` functions (and eventually the default resolution behavior); returning `false` signals that `source` should be treated as an external module and not included in the bundle. If you return an object, then it is possible to resolve an import to a different id while excluding it from the bundle at the same time. This allows you to replace dependencies with external dependencies without the need for the user to mark them as "external" manually via the `external` option: ```js -resolveId(id) { - if (id === 'my-dependency') { - return {id: 'my-dependency-develop', external: true}; +resolveId(source) { + if (source === 'my-dependency') { + return {source: 'my-dependency-develop', external: true}; } return null; } @@ -272,7 +281,7 @@ Kind: `async, parallel` Called only at the end of `bundle.write()` once all files have been written. Similar to the [`generateBundle`](guide/en#generatebundle) hook, `bundle` provides the full list of files being written along with their details. -### Deprecated +### Deprecated Hooks ☢️ These hooks have been deprecated and may be removed in a future Rollup version. @@ -347,10 +356,6 @@ Returns additional information about the module in question in the form If the module id cannot be found, an error is thrown. -#### `this.isExternal(id: string, parentId: string, isResolved: boolean): boolean` - -Determine if a given module ID is external. - #### `this.meta: {rollupVersion: string}` An `Object` containing potentially useful Rollup metadata. `meta` is the only context property accessible from the [`options`](guide/en#options) hook. @@ -369,9 +374,8 @@ or converted into an Array via `Array.from(this.moduleIds)`. Use Rollup's internal acorn instance to parse code to an AST. -#### `this.resolveId(importee: string, importer: string) => Promise` - -Resolve imports to module ids (i.e. file names). Uses the same hooks as Rollup itself. +#### `this.resolve(source: string, importer: string) => Promise<{id: string, external: boolean} | null>` +Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses, and determine if an import should be external. If `null` is returned, the import could not be resolved by Rollup or any plugin but was not explicitly marked as external by the user. #### `this.setAssetSource(assetReferenceId: string, source: string | Buffer) => void` @@ -393,6 +397,14 @@ Use the second form if you need to add additional properties to your warning obj The `position` argument is a character index where the warning was raised. If present, Rollup will augment the warning object with `pos`, `loc` (a standard `{ file, line, column }` object) and `frame` (a snippet of code showing the error). +### Deprecated Context Functions + +☢️ These context utility functions have been deprecated and may be removed in a future Rollup version. + +- `this.isExternal(id: string, importer: string, isResolved: boolean): boolean` - _**Use [`this.resolve`](guide/en#this-resolve-source-string-importer-string-promise-id-string-external-boolean-null)**_ - Determine if a given module ID is external when imported by `importer`. When `isResolved` is false, Rollup will try to resolve the id before testing if it is external. + +- `this.resolveId(source: string, importer: string) => Promise` - _**Use [`this.resolve`](guide/en#this-resolve-source-string-importer-string-promise-id-string-external-boolean-null)**_ - Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses. Returns `null` if an id cannot be resolved. + ### Asset URLs To reference an asset URL reference from within JS code, use the `import.meta.ROLLUP_ASSET_URL_assetReferenceId` replacement. This will generate code that depends on the output format and generates a URL that points to the emitted file in the target environment. Note that all formats except CommonJS and UMD assume that they run in a browser environment where `URL` and `document` are available. @@ -403,9 +415,9 @@ The following example will detect imports of `.svg` files, emit the imported fil // plugin export default function svgResolverPlugin () { return ({ - resolveId(id, importee) { - if (id.endsWith('.svg')) { - return path.resolve(path.dirname(importee), id); + resolveId(source, importer) { + if (source.endsWith('.svg')) { + return path.resolve(path.dirname(importer), source); } }, load(id) { @@ -445,11 +457,11 @@ export default function paintWorkletPlugin () { )});`; } }, - resolveId(id, importee) { + resolveId(source, importer) { // We remove the prefix, resolve everything to absolute ids and add the prefix again // This makes sure that you can use relative imports to define worklets - if (id.startsWith(REGISTER_WORKLET)) { - return this.resolveId(id.slice(REGISTER_WORKLET.length), importee).then( + if (source.startsWith(REGISTER_WORKLET)) { + return this.resolveId(source.slice(REGISTER_WORKLET.length), importer).then( id => REGISTER_WORKLET + id ); } diff --git a/src/Chunk.ts b/src/Chunk.ts index 5eeff82240f..f6df6ad2ba6 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -557,8 +557,10 @@ export default class Chunk { }); } + this.setExternalRenderPaths(options, inputBase); + this.renderedDeclarations = { - dependencies: this.getChunkDependencyDeclarations(options, inputBase), + dependencies: this.getChunkDependencyDeclarations(options), exports: this.exportMode === 'none' ? [] : this.getChunkExportDeclarations() }; @@ -802,7 +804,12 @@ export default class Chunk { node.renderFinalResolution(code, `'${relPath}'`, format); } } else if (resolution instanceof ExternalModule) { - node.renderFinalResolution(code, `'${resolution.id}'`, format); + let resolutionId = resolution.id; + if (resolution.renormalizeRenderPath) { + resolutionId = normalize(relative(dirname(this.id), resolution.renderPath)); + if (!resolutionId.startsWith('../')) resolutionId = './' + resolutionId; + } + node.renderFinalResolution(code, `'${resolutionId}'`, format); } else { node.renderFinalResolution(code, resolution, format); } @@ -826,10 +833,7 @@ export default class Chunk { return needsAmdModule; } - private getChunkDependencyDeclarations( - options: OutputOptions, - inputBase: string - ): ChunkDependencies { + private getChunkDependencyDeclarations(options: OutputOptions): ChunkDependencies { const reexportDeclarations = new Map(); for (let exportName of this.getExportNames()) { @@ -902,7 +906,7 @@ export default class Chunk { let id: string; let globalName: string; if (dep instanceof ExternalModule) { - id = dep.setRenderPath(options, inputBase); + id = dep.renderPath; if (options.format === 'umd' || options.format === 'iife') { globalName = getGlobalName( dep, @@ -1012,7 +1016,7 @@ export default class Chunk { node.setResolution(false); } } else if (resolution instanceof ExternalModule) { - node.setResolution(true); + node.setResolution(false); } else { node.setResolution(false); } @@ -1020,6 +1024,14 @@ export default class Chunk { } } + private setExternalRenderPaths(options: OutputOptions, inputBase: string) { + for (const dependency of this.dependencies.concat(this.dynamicDependencies)) { + if (dependency instanceof ExternalModule) { + dependency.setRenderPath(options, inputBase); + } + } + } + private setIdentifierRenderResolutions(options: OutputOptions) { for (const exportName of this.getExportNames()) { const exportVariable = this.exportNames[exportName]; diff --git a/src/Module.ts b/src/Module.ts index b0c82fcb352..f96737ce7cc 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -172,7 +172,6 @@ export default class Module { dynamicallyImportedBy: Module[] = []; dynamicDependencies: (Module | ExternalModule)[] = []; dynamicImports: { - alias: string | null; node: Import; resolution: Module | ExternalModule | string | void; }[] = []; @@ -613,7 +612,7 @@ export default class Module { } private addDynamicImport(node: Import) { - this.dynamicImports.push({ node, alias: undefined, resolution: undefined }); + this.dynamicImports.push({ node, resolution: undefined }); } private addExport( diff --git a/src/ModuleLoader.ts b/src/ModuleLoader.ts index 524722ec41d..419b33ec6e2 100644 --- a/src/ModuleLoader.ts +++ b/src/ModuleLoader.ts @@ -11,15 +11,22 @@ import { SourceDescription } from './rollup/types'; import { + errBadLoader, + errCannotAssignModuleToChunk, + errChunkNotGeneratedForFileName, + errChunkReferenceIdNotFoundForFilename, + errEntryCannotBeExternal, + errInternalIdCannotBeExternal, + errNamespaceConflict, error, - errorCannotAssignModuleToChunk, - errorChunkNotGeneratedForFileName, - errorChunkReferenceIdNotFoundForFilename + errUnresolvedEntry, + errUnresolvedImport, + errUnresolvedImportTreatedAsExternal } from './utils/error'; import { isRelative, resolve } from './utils/path'; import { PluginDriver } from './utils/pluginDriver'; import { addWithNewReferenceId } from './utils/referenceIds'; -import relativeId, { getAliasName } from './utils/relativeId'; +import relativeId from './utils/relativeId'; import { timeEnd, timeStart } from './utils/timers'; import transform from './utils/transform'; @@ -32,8 +39,8 @@ interface UnresolvedEntryModuleWithAlias extends UnresolvedModuleWithAlias { isManualChunkEntry?: boolean; } -function normalizeRelativeExternalId(importee: string, source: string) { - return isRelative(source) ? resolve(importee, '..', source) : source; +function normalizeRelativeExternalId(importer: string, source: string) { + return isRelative(source) ? resolve(importer, '..', source) : source; } export class ModuleLoader { @@ -139,16 +146,24 @@ export class ModuleLoader { getChunkFileName(referenceId: string): string { const entryRecord = this.entriesByReferenceId.get(referenceId); - if (!entryRecord) errorChunkReferenceIdNotFoundForFilename(referenceId); + if (!entryRecord) error(errChunkReferenceIdNotFoundForFilename(referenceId)); const fileName = entryRecord.module && (entryRecord.module.facadeChunk ? entryRecord.module.facadeChunk.id : entryRecord.module.chunk.id); - if (!fileName) errorChunkNotGeneratedForFileName(entryRecord); + if (!fileName) error(errChunkNotGeneratedForFileName(entryRecord)); return fileName; } + resolveId(source: string, importer: string): Promise { + return Promise.resolve( + this.isExternal(source, importer, false) + ? { id: source, external: true } + : this.pluginDriver.hookFirst('resolveId', [source, importer]) + ).then((result: ResolveIdResult) => this.normalizeResolveIdResult(result, importer, source)); + } + private awaitLoadModulesPromise(loadNewModulesPromise: Promise): Promise { this.latestLoadModulesPromise = Promise.all([ loadNewModulesPromise, @@ -169,38 +184,22 @@ export class ModuleLoader { private fetchAllDependencies(module: Module) { const fetchDynamicImportsPromise = Promise.all( - module.getDynamicImportExpressions().map((dynamicImportExpression, index) => - // TODO we only should expose the acorn AST here - this.pluginDriver - .hookFirst('resolveDynamicImport', [ - dynamicImportExpression as string | ESTree.Node, - module.id - ]) - .then((replacement: string | void) => { - if (!replacement) return; - const dynamicImport = module.dynamicImports[index]; - dynamicImport.alias = getAliasName(replacement); - if (typeof dynamicImportExpression !== 'string') { - dynamicImport.resolution = replacement; - } else if (this.isExternal(replacement, module.id, true)) { - let externalModule; - if (!this.modulesById.has(replacement)) { - externalModule = new ExternalModule({ - graph: this.graph, - id: replacement - }); - this.modulesById.set(replacement, module); - } else { - externalModule = this.modulesById.get(replacement); - } - dynamicImport.resolution = externalModule; - externalModule.exportsNamespace = true; - } else { - return this.fetchModule(replacement, module.id).then(depModule => { - dynamicImport.resolution = depModule; - }); - } - }) + module.getDynamicImportExpressions().map((specifier, index) => + this.resolveDynamicImport(specifier as string | ESTree.Node, module.id).then(resolvedId => { + if (resolvedId === null) return; + const dynamicImport = module.dynamicImports[index]; + if (typeof resolvedId === 'string') { + dynamicImport.resolution = resolvedId; + return; + } + return this.fetchResolvedDependency( + relativeId(resolvedId.id), + module.id, + resolvedId + ).then(module => { + dynamicImport.resolution = module; + }); + }) ) ); fetchDynamicImportsPromise.catch(() => {}); @@ -236,13 +235,7 @@ export class ModuleLoader { timeEnd('load modules', 3); if (typeof source === 'string') return source; if (source && typeof source === 'object' && typeof source.code === 'string') return source; - - error({ - code: 'BAD_LOADER', - message: `Error loading ${relativeId( - id - )}: plugin load hook should return a string, a { code, map } object, or nothing/null` - }); + error(errBadLoader(id)); }) .then(source => { const sourceDescription: SourceDescription = @@ -283,25 +276,13 @@ export class ModuleLoader { module.exportAllSources.forEach(source => { const id = module.resolvedIds[source].id; const exportAllModule = this.modulesById.get(id); - if (exportAllModule.isExternal) return; + if (exportAllModule instanceof ExternalModule) return; - for (const name in (exportAllModule).exportsAll) { + for (const name in exportAllModule.exportsAll) { if (name in module.exportsAll) { - this.graph.warn({ - code: 'NAMESPACE_CONFLICT', - message: `Conflicting namespaces: ${relativeId( - module.id - )} re-exports '${name}' from both ${relativeId( - module.exportsAll[name] - )} and ${relativeId( - (exportAllModule).exportsAll[name] - )} (will be ignored)`, - name, - reexporter: module.id, - sources: [module.exportsAll[name], (exportAllModule).exportsAll[name]] - }); + this.graph.warn(errNamespaceConflict(name, module, exportAllModule)); } else { - module.exportsAll[name] = (exportAllModule).exportsAll[name]; + module.exportsAll[name] = exportAllModule.exportsAll[name]; } } }); @@ -310,50 +291,89 @@ export class ModuleLoader { }); } + private fetchResolvedDependency( + source: string, + importer: string, + resolvedId: ResolvedId + ): Promise { + if (resolvedId.external) { + if (!this.modulesById.has(resolvedId.id)) { + this.modulesById.set( + resolvedId.id, + new ExternalModule({ graph: this.graph, id: resolvedId.id }) + ); + } + + const externalModule = this.modulesById.get(resolvedId.id); + if (externalModule instanceof ExternalModule === false) { + error(errInternalIdCannotBeExternal(source, importer)); + } + return Promise.resolve(externalModule); + } else { + return this.fetchModule(resolvedId.id, importer); + } + } + + private handleMissingImports( + resolvedId: ResolvedId | null, + source: string, + importer: string + ): ResolvedId { + if (resolvedId === null) { + if (isRelative(source)) { + error(errUnresolvedImport(source, importer)); + } + this.graph.warn(errUnresolvedImportTreatedAsExternal(source, importer)); + return { id: source, external: true }; + } + return resolvedId; + } + private loadEntryModule = ({ alias, unresolvedId, isManualChunkEntry - }: UnresolvedEntryModuleWithAlias): Promise => { - return this.pluginDriver.hookFirst('resolveId', [unresolvedId, undefined]).then(id => { - if (id === false) { - error({ - code: 'UNRESOLVED_ENTRY', - message: `Entry module cannot be external` - }); - } - - if (id == null) { - error({ - code: 'UNRESOLVED_ENTRY', - message: `Could not resolve entry (${unresolvedId})` - }); - } + }: UnresolvedEntryModuleWithAlias): Promise => + this.pluginDriver + .hookFirst('resolveId', [unresolvedId, undefined]) + .then((resolveIdResult: ResolveIdResult) => { + if ( + resolveIdResult === false || + (resolveIdResult && typeof resolveIdResult === 'object' && resolveIdResult.external) + ) { + error(errEntryCannotBeExternal(unresolvedId)); + } + const id = + resolveIdResult && typeof resolveIdResult === 'object' + ? resolveIdResult.id + : resolveIdResult; - return this.fetchModule(id, undefined).then(module => { - if (alias !== null) { - if (isManualChunkEntry) { - if (module.manualChunkAlias !== null && module.manualChunkAlias !== alias) { - errorCannotAssignModuleToChunk(module.id, alias, module.manualChunkAlias); + if (typeof id === 'string') { + return this.fetchModule(id, undefined).then(module => { + if (alias !== null) { + if (isManualChunkEntry) { + if (module.manualChunkAlias !== null && module.manualChunkAlias !== alias) { + error(errCannotAssignModuleToChunk(module.id, alias, module.manualChunkAlias)); + } + module.manualChunkAlias = alias; + return module; + } + if (module.chunkAlias !== null && module.chunkAlias !== alias) { + error(errCannotAssignModuleToChunk(module.id, alias, module.chunkAlias)); + } + module.chunkAlias = alias; } - module.manualChunkAlias = alias; return module; - } - if (module.chunkAlias !== null && module.chunkAlias !== alias) { - errorCannotAssignModuleToChunk(module.id, alias, module.chunkAlias); - } - module.chunkAlias = alias; + }); } - return module; + error(errUnresolvedEntry(unresolvedId)); }); - }); - }; private normalizeResolveIdResult( resolveIdResult: ResolveIdResult, - module: Module, + importer: string, source: string - ): ResolvedId { + ): ResolvedId | null { let id = ''; let external = false; if (resolveIdResult) { @@ -364,67 +384,68 @@ export class ModuleLoader { } } else { id = resolveIdResult; - if (this.isExternal(id, module.id, true)) { + if (this.isExternal(id, importer, true)) { external = true; } } if (external) { - id = normalizeRelativeExternalId(module.id, id); + id = normalizeRelativeExternalId(importer, id); } } else { - id = normalizeRelativeExternalId(module.id, source); - external = true; - if (resolveIdResult !== false && !this.isExternal(id, module.id, true)) { - if (isRelative(source)) { - error({ - code: 'UNRESOLVED_IMPORT', - message: `Could not resolve '${source}' from ${relativeId(module.id)}` - }); - } - this.graph.warn({ - code: 'UNRESOLVED_IMPORT', - importer: relativeId(module.id), - message: `'${source}' is imported by ${relativeId( - module.id - )}, but could not be resolved – treating it as an external dependency`, - source, - url: 'https://rollupjs.org/guide/en#warning-treating-module-as-external-dependency' - }); + id = normalizeRelativeExternalId(importer, source); + if (resolveIdResult !== false && !this.isExternal(id, importer, true)) { + return null; } + external = true; } return { id, external }; } - private resolveAndFetchDependency(module: Module, source: string): Promise { + private resolveAndFetchDependency( + module: Module, + source: string + ): Promise { return Promise.resolve( module.resolvedIds[source] || - Promise.resolve( - this.isExternal(source, module.id, false) - ? { id: source, external: true } - : this.pluginDriver.hookFirst('resolveId', [source, module.id]) - ).then((result: ResolveIdResult) => this.normalizeResolveIdResult(result, module, source)) + this.resolveId(source, module.id).then(resolvedId => + this.handleMissingImports(resolvedId, source, module.id) + ) ).then(resolvedId => { module.resolvedIds[source] = resolvedId; - if (resolvedId.external) { - if (!this.modulesById.has(resolvedId.id)) { - this.modulesById.set( - resolvedId.id, - new ExternalModule({ graph: this.graph, id: resolvedId.id }) - ); - } + return this.fetchResolvedDependency(source, module.id, resolvedId); + }); + } - const externalModule = this.modulesById.get(resolvedId.id); - if (externalModule instanceof ExternalModule === false) { - error({ - code: 'INVALID_EXTERNAL_ID', - message: `'${source}' is imported as an external by ${relativeId( - module.id - )}, but is already an existing non-external module id.` - }); + private resolveDynamicImport( + specifier: string | ESTree.Node, + importer: string + ): Promise { + // TODO we only should expose the acorn AST here + return this.pluginDriver + .hookFirst('resolveDynamicImport', [specifier, importer]) + .then((resolution: ResolveIdResult) => { + if (typeof specifier !== 'string') { + if (typeof resolution === 'string') { + return resolution; + } + if (!resolution) { + return null; + } + return { + external: false, + ...resolution + }; } - } else { - return this.fetchModule(resolvedId.id, module.id); - } - }); + if (resolution == null) { + return this.resolveId(specifier, importer).then(resolvedId => + this.handleMissingImports(resolvedId, specifier, importer) + ); + } + return this.handleMissingImports( + this.normalizeResolveIdResult(resolution, importer, specifier), + specifier, + importer + ); + }); } } diff --git a/src/rollup/index.ts b/src/rollup/index.ts index f35cf6aca88..4a40443f850 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -433,9 +433,8 @@ function normalizeOutputOptions( // now outputOptions is an array, but rollup.rollup API doesn't support arrays const mergedOutputOptions = mergedOptions.outputOptions[0]; - const outputOptionsReducer = (outputOptions: OutputOptions, result: OutputOptions) => { - return result || outputOptions; - }; + const outputOptionsReducer = (outputOptions: OutputOptions, result: OutputOptions) => + result || outputOptions; const outputOptions = pluginDriver.hookReduceArg0Sync( 'outputOptions', [mergedOutputOptions], diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 19f07e2fe99..1f1b37736cf 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -121,10 +121,13 @@ export interface PluginContext extends MinimalPluginContext { importedIds: string[]; isExternal: boolean; }; + /** @deprecated */ isExternal: IsExternal; moduleIds: IterableIterator; parse: (input: string, options: any) => ESTree.Program; - resolveId: (id: string, parent: string) => Promise; + resolve: (source: string, importer: string) => Promise; + /** @deprecated */ + resolveId: (source: string, importer: string) => Promise; setAssetSource: (assetReferenceId: string, source: string | Buffer) => void; warn: (warning: RollupWarning | string, pos?: { column: number; line: number }) => void; /** @deprecated */ @@ -136,23 +139,25 @@ export interface PluginContextMeta { } export interface ResolvedId { - external?: boolean | void; + external: boolean; id: string; } -export type ResolveIdResult = string | false | void | ResolvedId; - export interface ResolvedIdMap { [key: string]: ResolvedId; } +type PartialResolvedId = Partial & { id: string }; + +export type ResolveIdResult = string | false | void | PartialResolvedId; + export type ResolveIdHook = ( this: PluginContext, - id: string, - parent: string + source: string, + importer: string ) => Promise | ResolveIdResult; -export type IsExternal = (id: string, parentId: string, isResolved: boolean) => boolean | void; +export type IsExternal = (source: string, importer: string, isResolved: boolean) => boolean | void; export type LoadHook = ( this: PluginContext, @@ -194,8 +199,8 @@ export type RenderChunkHook = ( export type ResolveDynamicImportHook = ( this: PluginContext, specifier: string | ESTree.Node, - parentId: string -) => Promise | string | void; + importer: string +) => Promise | ResolveIdResult; export type ResolveImportMetaHook = ( this: PluginContext, diff --git a/src/utils/assetHooks.ts b/src/utils/assetHooks.ts index 3d3b66a0be4..a2b24e4d20c 100644 --- a/src/utils/assetHooks.ts +++ b/src/utils/assetHooks.ts @@ -1,13 +1,14 @@ import sha256 from 'hash.js/lib/hash/sha/256'; import { Asset, EmitAsset, OutputBundle } from '../rollup/types'; import { - errorAssetNotFinalisedForFileName, - errorAssetReferenceIdNotFoundForFilename, - errorAssetReferenceIdNotFoundForSetSource, - errorAssetSourceAlreadySet, - errorAssetSourceMissingForSetSource, - errorInvalidAssetName, - errorNoAssetSourceSet + errAssetNotFinalisedForFileName, + errAssetReferenceIdNotFoundForFilename, + errAssetReferenceIdNotFoundForSetSource, + errAssetSourceAlreadySet, + errAssetSourceMissingForSetSource, + errInvalidAssetName, + errNoAssetSourceSet, + error } from './error'; import { extname } from './path'; import { addWithNewReferenceId } from './referenceIds'; @@ -19,7 +20,7 @@ export function getAssetFileName( existingNames: Record, assetFileNames: string ) { - if (asset.source === undefined) errorNoAssetSourceSet(asset); + if (asset.source === undefined) error(errNoAssetSourceSet(asset)); if (asset.fileName) return asset.fileName; return makeUnique( @@ -50,7 +51,7 @@ export function createAssetPluginHooks( ) { return { emitAsset(name: string, source?: string | Buffer) { - if (typeof name !== 'string' || !isPlainName(name)) errorInvalidAssetName(name); + if (typeof name !== 'string' || !isPlainName(name)) error(errInvalidAssetName(name)); const asset: Asset = { name, source, fileName: undefined }; if (outputBundle && source !== undefined) finaliseAsset(asset, outputBundle, assetFileNames); return addWithNewReferenceId(asset, assetsByReferenceId, name); @@ -58,17 +59,17 @@ export function createAssetPluginHooks( setAssetSource(assetReferenceId: string, source?: string | Buffer) { const asset = assetsByReferenceId.get(assetReferenceId); - if (!asset) errorAssetReferenceIdNotFoundForSetSource(assetReferenceId); - if (asset.source !== undefined) errorAssetSourceAlreadySet(asset); - if (typeof source !== 'string' && !source) errorAssetSourceMissingForSetSource(asset); + if (!asset) error(errAssetReferenceIdNotFoundForSetSource(assetReferenceId)); + if (asset.source !== undefined) error(errAssetSourceAlreadySet(asset)); + if (typeof source !== 'string' && !source) error(errAssetSourceMissingForSetSource(asset)); asset.source = source; if (outputBundle) finaliseAsset(asset, outputBundle, assetFileNames); }, getAssetFileName(assetReferenceId: string) { const asset = assetsByReferenceId.get(assetReferenceId); - if (!asset) errorAssetReferenceIdNotFoundForFilename(assetReferenceId); - if (asset.fileName === undefined) errorAssetNotFinalisedForFileName(asset); + if (!asset) error(errAssetReferenceIdNotFoundForFilename(assetReferenceId)); + if (asset.fileName === undefined) error(errAssetNotFinalisedForFileName(asset)); return asset.fileName; } }; diff --git a/src/utils/defaultPlugin.ts b/src/utils/defaultPlugin.ts index c5b6f390cf8..f447699ff2e 100644 --- a/src/utils/defaultPlugin.ts +++ b/src/utils/defaultPlugin.ts @@ -1,20 +1,15 @@ -import { InputOptions, Plugin } from '../rollup/types'; +import { Plugin } from '../rollup/types'; import { error } from './error'; import { lstatSync, readdirSync, readFileSync, realpathSync } from './fs'; import { basename, dirname, isAbsolute, resolve } from './path'; -export function getRollupDefaultPlugin(options: InputOptions): Plugin { +export function getRollupDefaultPlugin(preserveSymlinks: boolean): Plugin { return { name: 'Rollup Core', - resolveId: createResolveId(options), + resolveId: createResolveId(preserveSymlinks), load(id) { return readFileSync(id, 'utf-8'); }, - resolveDynamicImport(specifier, parentId) { - if (typeof specifier === 'string' && !this.isExternal(specifier, parentId, false)) - // TODO this typecast will cause problems if resolveId returns false or an object - return >this.resolveId(specifier, parentId); - }, resolveFileUrl({ relativePath, format }) { return relativeUrlMechanisms[format](relativePath); }, @@ -53,8 +48,8 @@ function addJsExtensionIfNecessary(file: string, preserveSymlinks: boolean) { return found; } -function createResolveId(options: InputOptions) { - return function(importee: string, importer: string) { +function createResolveId(preserveSymlinks: boolean) { + return function(source: string, importer: string) { if (typeof process === 'undefined') { error({ code: 'MISSING_PROCESS', @@ -65,15 +60,15 @@ function createResolveId(options: InputOptions) { // external modules (non-entry modules that start with neither '.' or '/') // are skipped at this stage. - if (importer !== undefined && !isAbsolute(importee) && importee[0] !== '.') return null; + if (importer !== undefined && !isAbsolute(source) && source[0] !== '.') return null; // `resolve` processes paths from right to left, prepending them until an // absolute path is created. Absolute importees therefore shortcircuit the // resolve call and require no special handing on our part. // See https://nodejs.org/api/path.html#path_path_resolve_paths return addJsExtensionIfNecessary( - resolve(importer ? dirname(importer) : resolve(), importee), - options.preserveSymlinks + resolve(importer ? dirname(importer) : resolve(), source), + preserveSymlinks ); }; } diff --git a/src/utils/error.ts b/src/utils/error.ts index dd2fe14e979..95e1f460805 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -1,4 +1,5 @@ import { locate } from 'locate-character'; +import Module from '../Module'; import { Asset, RollupError, RollupWarning } from '../rollup/types'; import getCodeFrame from './getCodeFrame'; import relativeId from './relativeId'; @@ -35,91 +36,180 @@ export enum Errors { ASSET_NOT_FOUND = 'ASSET_NOT_FOUND', ASSET_SOURCE_ALREADY_SET = 'ASSET_SOURCE_ALREADY_SET', ASSET_SOURCE_MISSING = 'ASSET_SOURCE_MISSING', + BAD_LOADER = 'BAD_LOADER', CHUNK_NOT_FOUND = 'CHUNK_NOT_FOUND', CHUNK_NOT_GENERATED = 'CHUNK_NOT_GENERATED', INVALID_ASSET_NAME = 'INVALID_ASSET_NAME', INVALID_CHUNK = 'INVALID_CHUNK', - INVALID_ROLLUP_PHASE = 'INVALID_ROLLUP_PHASE' + INVALID_EXTERNAL_ID = 'INVALID_EXTERNAL_ID', + INVALID_PLUGIN_HOOK = 'INVALID_PLUGIN_HOOK', + INVALID_ROLLUP_PHASE = 'INVALID_ROLLUP_PHASE', + NAMESPACE_CONFLICT = 'NAMESPACE_CONFLICT', + UNRESOLVED_ENTRY = 'UNRESOLVED_ENTRY', + UNRESOLVED_IMPORT = 'UNRESOLVED_IMPORT' } -export function errorAssetNotFinalisedForFileName(asset: Asset) { - error({ +export function errAssetNotFinalisedForFileName(asset: Asset) { + return { code: Errors.ASSET_NOT_FINALISED, message: `Plugin error - Unable to get file name for asset "${ asset.name }". Ensure that the source is set and that generate is called first.` - }); + }; } -export function errorChunkNotGeneratedForFileName(entry: { name: string }) { - error({ +export function errChunkNotGeneratedForFileName(entry: { name: string }) { + return { code: Errors.CHUNK_NOT_GENERATED, message: `Plugin error - Unable to get file name for chunk "${ entry.name }". Ensure that generate is called first.` - }); + }; } -export function errorAssetReferenceIdNotFoundForFilename(assetReferenceId: string) { - error({ +export function errAssetReferenceIdNotFoundForFilename(assetReferenceId: string) { + return { code: Errors.ASSET_NOT_FOUND, message: `Plugin error - Unable to get file name for unknown asset "${assetReferenceId}".` - }); + }; } -export function errorAssetReferenceIdNotFoundForSetSource(assetReferenceId: string) { - error({ +export function errAssetReferenceIdNotFoundForSetSource(assetReferenceId: string) { + return { code: Errors.ASSET_NOT_FOUND, message: `Plugin error - Unable to set the source for unknown asset "${assetReferenceId}".` - }); + }; } -export function errorAssetSourceAlreadySet(asset: Asset) { - error({ +export function errAssetSourceAlreadySet(asset: Asset) { + return { code: Errors.ASSET_SOURCE_ALREADY_SET, message: `Plugin error - Unable to set the source for asset "${ asset.name }", source already set.` - }); + }; } -export function errorAssetSourceMissingForSetSource(asset: Asset) { - error({ +export function errAssetSourceMissingForSetSource(asset: Asset) { + return { code: Errors.ASSET_SOURCE_MISSING, message: `Plugin error creating asset "${asset.name}", setAssetSource call without a source.` - }); + }; } -export function errorNoAssetSourceSet(asset: Asset) { - error({ +export function errNoAssetSourceSet(asset: Asset) { + return { code: Errors.ASSET_SOURCE_MISSING, message: `Plugin error creating asset "${asset.name}" - no asset source set.` - }); + }; } -export function errorChunkReferenceIdNotFoundForFilename(chunkReferenceId: string) { - error({ +export function errBadLoader(id: string) { + return { + code: Errors.BAD_LOADER, + message: `Error loading ${relativeId( + id + )}: plugin load hook should return a string, a { code, map } object, or nothing/null` + }; +} + +export function errChunkReferenceIdNotFoundForFilename(chunkReferenceId: string) { + return { code: Errors.CHUNK_NOT_FOUND, message: `Plugin error - Unable to get file name for unknown chunk "${chunkReferenceId}".` - }); + }; } -export function errorInvalidAssetName(name: string) { - error({ +export function errInvalidAssetName(name: string) { + return { code: Errors.INVALID_ASSET_NAME, message: `Plugin error creating asset, name "${name}" is not a plain (non relative or absolute URL) string name.` - }); + }; } -export function errorCannotAssignModuleToChunk( +export function errCannotAssignModuleToChunk( moduleId: string, assignToAlias: string, currentAlias: string ) { - error({ + return { code: Errors.INVALID_CHUNK, message: `Cannot assign ${relativeId( moduleId )} to the "${assignToAlias}" chunk as it is already in the "${currentAlias}" chunk.` - }); + }; +} + +export function errInternalIdCannotBeExternal(source: string, importer: string) { + return { + code: Errors.INVALID_EXTERNAL_ID, + message: `'${source}' is imported as an external by ${relativeId( + importer + )}, but is already an existing non-external module id.` + }; +} + +export function errInvalidRollupPhaseForAddWatchFile() { + return { + code: Errors.INVALID_ROLLUP_PHASE, + message: `Cannot call addWatchFile after the build has finished.` + }; +} + +export function errInvalidRollupPhaseForEmitChunk() { + return { + code: Errors.INVALID_ROLLUP_PHASE, + message: `Cannot call emitChunk after module loading has finished.` + }; +} + +export function errNamespaceConflict( + name: string, + reexportingModule: Module, + additionalExportAllModule: Module +) { + return { + code: Errors.NAMESPACE_CONFLICT, + message: `Conflicting namespaces: ${relativeId( + reexportingModule.id + )} re-exports '${name}' from both ${relativeId( + reexportingModule.exportsAll[name] + )} and ${relativeId(additionalExportAllModule.exportsAll[name])} (will be ignored)`, + name, + reexporter: reexportingModule.id, + sources: [reexportingModule.exportsAll[name], additionalExportAllModule.exportsAll[name]] + }; +} + +export function errEntryCannotBeExternal(unresolvedId: string) { + return { + code: Errors.UNRESOLVED_ENTRY, + message: `Entry module cannot be external (${relativeId(unresolvedId)}).` + }; +} + +export function errUnresolvedEntry(unresolvedId: string) { + return { + code: Errors.UNRESOLVED_ENTRY, + message: `Could not resolve entry module (${relativeId(unresolvedId)}).` + }; +} + +export function errUnresolvedImport(source: string, importer: string) { + return { + code: Errors.UNRESOLVED_IMPORT, + message: `Could not resolve '${source}' from ${relativeId(importer)}` + }; +} + +export function errUnresolvedImportTreatedAsExternal(source: string, importer: string) { + return { + code: Errors.UNRESOLVED_IMPORT, + importer: relativeId(importer), + message: `'${source}' is imported by ${relativeId( + importer + )}, but could not be resolved – treating it as an external dependency`, + source, + url: 'https://rollupjs.org/guide/en#warning-treating-module-as-external-dependency' + }; } diff --git a/src/utils/pluginDriver.ts b/src/utils/pluginDriver.ts index f1464e0171b..cea0d193bbe 100644 --- a/src/utils/pluginDriver.ts +++ b/src/utils/pluginDriver.ts @@ -16,7 +16,11 @@ import { import { createAssetPluginHooks } from './assetHooks'; import { BuildPhase } from './buildPhase'; import { getRollupDefaultPlugin } from './defaultPlugin'; -import { error, Errors } from './error'; +import { + errInvalidRollupPhaseForAddWatchFile, + errInvalidRollupPhaseForEmitChunk, + error +} from './error'; import { NameCollection } from './reservedNames'; type Args = T extends (...args: infer K) => any ? K : never; @@ -87,7 +91,7 @@ export function createPluginDriver( pluginCache: Record, watcher?: RollupWatcher ): PluginDriver { - const plugins = [...(options.plugins || []), getRollupDefaultPlugin(options)]; + const plugins = [...(options.plugins || []), getRollupDefaultPlugin(options.preserveSymlinks)]; const { emitAsset, getAssetFileName, setAssetSource } = createAssetPluginHooks(graph.assetsById); const existingPluginKeys: NameCollection = {}; @@ -136,21 +140,14 @@ export function createPluginDriver( const context: PluginContext = { addWatchFile(id) { - if (graph.phase >= BuildPhase.GENERATE) - this.error({ - code: Errors.INVALID_ROLLUP_PHASE, - message: `Cannot call addWatchFile after the build has finished.` - }); + if (graph.phase >= BuildPhase.GENERATE) this.error(errInvalidRollupPhaseForAddWatchFile()); graph.watchFiles[id] = true; }, cache: cacheInstance, emitAsset, emitChunk(id, options) { if (graph.phase > BuildPhase.LOAD_AND_PARSE) - this.error({ - code: Errors.INVALID_ROLLUP_PHASE, - message: `Cannot call emitChunk after module loading has finished.` - }); + this.error(errInvalidRollupPhaseForEmitChunk()); return graph.moduleLoader.addEntryModuleAndGetReferenceId({ alias: (options && options.name) || null, unresolvedId: id @@ -189,8 +186,13 @@ export function createPluginDriver( }, moduleIds: graph.moduleById.keys(), parse: graph.contextParse, - resolveId(id, parent) { - return pluginDriver.hookFirst('resolveId', [id, parent]); + resolveId(source, importer) { + return graph.moduleLoader + .resolveId(source, importer) + .then(resolveId => resolveId && resolveId.id); + }, + resolve(source, importer) { + return graph.moduleLoader.resolveId(source, importer); }, setAssetSource, warn(warning) { @@ -358,9 +360,9 @@ export function createPluginDriver( promise = promise.then(arg0 => { const hookPromise = runHook(name, [arg0, ...args], i, false, hookContext); if (!hookPromise) return arg0; - return hookPromise.then((result: any) => { - return reduce.call(pluginContexts[i], arg0, result, plugins[i]); - }); + return hookPromise.then((result: any) => + reduce.call(pluginContexts[i], arg0, result, plugins[i]) + ); }); } return promise; diff --git a/test/chunking-form/samples/dynamic-import-comments/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-comments/_expected/amd/main.js index 6e19fb3714f..5d7a227c6c1 100644 --- a/test/chunking-form/samples/dynamic-import-comments/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-comments/_expected/amd/main.js @@ -2,6 +2,6 @@ define(['require'], function (require) { 'use strict'; new Promise(function (resolve, reject) { require([ /* webpackChunkName: "chunk-name" */ - './foo.js'/*suffix*/], resolve, reject) }); + './foo'/*suffix*/], resolve, reject) }); }); diff --git a/test/chunking-form/samples/dynamic-import-external/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-external/_expected/amd/main.js index b81e4d74b05..571a87ecba4 100644 --- a/test/chunking-form/samples/dynamic-import-external/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-external/_expected/amd/main.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(['./foo.js'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./foo'], resolve, reject) }); }); diff --git a/test/chunking-form/samples/dynamic-import-name/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-name/_expected/amd/main.js index a17abe669db..ed174177324 100644 --- a/test/chunking-form/samples/dynamic-import-name/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-name/_expected/amd/main.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(['./foo.js'], resolve, reject) }).then(result => console.log(result)); + new Promise(function (resolve, reject) { require(['./foo'], resolve, reject) }).then(result => console.log(result)); }); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_config.js b/test/chunking-form/samples/resolve-dynamic-import/_config.js new file mode 100644 index 00000000000..fc84d61a62e --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_config.js @@ -0,0 +1,75 @@ +const path = require('path'); +const EXISTING = path.resolve(__dirname, 'existing.js'); + +module.exports = { + description: 'Supports all resolution formats for dynamic imports', + options: { + plugins: { + resolveId(source) { + switch (source) { + case 'existing-name': + return EXISTING; + case './direct-relative-external': + return false; + case './indirect-relative-external': + return { + id: 'to-indirect-relative-external', + external: true + }; + case 'direct-absolute-external': + return false; + case 'indirect-absolute-external': + return { + id: 'to-indirect-absolute-external', + external: true + }; + } + }, + + resolveDynamicImport(specifier) { + if (typeof specifier === 'string') { + switch (specifier) { + case 'existing-name': + return EXISTING; + case './direct-relative-external': + case '../direct-relative-external': + return false; + case './indirect-relative-external': + case '../indirect-relative-external': + return { + id: 'to-indirect-relative-external', + external: true + }; + case 'direct-absolute-external': + return false; + case 'indirect-absolute-external': + return { + id: 'to-indirect-absolute-external', + external: true + }; + default: + throw new Error(`Unexpected import ${specifier}`); + } + } + switch (specifier.left.value) { + case 'dynamic-direct-external': + return false; + case 'dynamic-indirect-external': + return { + id: 'to-dynamic-indirect-external', + external: true + }; + case 'dynamic-indirect-existing': + return { + id: EXISTING, + external: false + }; + case 'dynamic-replaced': + return `'my' + 'replacement'`; + default: + throw new Error(`Unexpected import ${specifier.left.value}`); + } + } + } + } +}; diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/generated-existing.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/generated-existing.js new file mode 100644 index 00000000000..e4849575ab9 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/generated-existing.js @@ -0,0 +1,7 @@ +define(['exports'], function (exports) { 'use strict'; + + const value = 'existing'; + + exports.value = value; + +}); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js new file mode 100644 index 00000000000..ab43e42d41c --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js @@ -0,0 +1,22 @@ +define(['require', './generated-existing', './direct-relative-external', 'to-indirect-relative-external', 'direct-absolute-external', 'to-indirect-absolute-external'], function (require, existing, directRelativeExternal, toIndirectRelativeExternal, directAbsoluteExternal, toIndirectAbsoluteExternal) { 'use strict'; + + // nested + new Promise(function (resolve, reject) { require(['./generated-existing'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./direct-relative-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['to-indirect-relative-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['direct-absolute-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['to-indirect-absolute-external'], resolve, reject) }); + + //main + new Promise(function (resolve, reject) { require(['./generated-existing'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./direct-relative-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['to-indirect-relative-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['direct-absolute-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['to-indirect-absolute-external'], resolve, reject) }); + + new Promise(function (resolve, reject) { require(['dynamic-direct-external' + unknown], resolve, reject) }); + new Promise(function (resolve, reject) { require(['to-dynamic-indirect-external'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./generated-existing'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['my' + 'replacement'], resolve, reject) }); + +}); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/generated-existing.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/generated-existing.js new file mode 100644 index 00000000000..561531ebe17 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/generated-existing.js @@ -0,0 +1,5 @@ +'use strict'; + +const value = 'existing'; + +exports.value = value; diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js new file mode 100644 index 00000000000..613f8edbf07 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js @@ -0,0 +1,26 @@ +'use strict'; + +require('./generated-existing.js'); +require('./direct-relative-external'); +require('to-indirect-relative-external'); +require('direct-absolute-external'); +require('to-indirect-absolute-external'); + +// nested +Promise.resolve(require('./generated-existing.js')); +Promise.resolve(require('./direct-relative-external')); +Promise.resolve(require('to-indirect-relative-external')); +Promise.resolve(require('direct-absolute-external')); +Promise.resolve(require('to-indirect-absolute-external')); + +//main +Promise.resolve(require('./generated-existing.js')); +Promise.resolve(require('./direct-relative-external')); +Promise.resolve(require('to-indirect-relative-external')); +Promise.resolve(require('direct-absolute-external')); +Promise.resolve(require('to-indirect-absolute-external')); + +Promise.resolve(require('dynamic-direct-external' + unknown)); +Promise.resolve(require('to-dynamic-indirect-external')); +Promise.resolve(require('./generated-existing.js')); +Promise.resolve(require('my' + 'replacement')); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/es/generated-existing.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/es/generated-existing.js new file mode 100644 index 00000000000..4eca34c7282 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/es/generated-existing.js @@ -0,0 +1,3 @@ +const value = 'existing'; + +export { value }; diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/es/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/es/main.js new file mode 100644 index 00000000000..7dacf7a3eee --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/es/main.js @@ -0,0 +1,24 @@ +import './generated-existing.js'; +import './direct-relative-external'; +import 'to-indirect-relative-external'; +import 'direct-absolute-external'; +import 'to-indirect-absolute-external'; + +// nested +import('./generated-existing.js'); +import('./direct-relative-external'); +import('to-indirect-relative-external'); +import('direct-absolute-external'); +import('to-indirect-absolute-external'); + +//main +import('./generated-existing.js'); +import('./direct-relative-external'); +import('to-indirect-relative-external'); +import('direct-absolute-external'); +import('to-indirect-absolute-external'); + +import('dynamic-direct-external' + unknown); +import('to-dynamic-indirect-external'); +import('./generated-existing.js'); +import('my' + 'replacement'); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/system/generated-existing.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/system/generated-existing.js new file mode 100644 index 00000000000..d7b47fdc482 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/system/generated-existing.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + const value = exports('value', 'existing'); + + } + }; +}); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/system/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/system/main.js new file mode 100644 index 00000000000..ea036d03331 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/system/main.js @@ -0,0 +1,28 @@ +System.register(['./generated-existing.js', './direct-relative-external', 'to-indirect-relative-external', 'direct-absolute-external', 'to-indirect-absolute-external'], function (exports, module) { + 'use strict'; + return { + setters: [function () {}, function () {}, function () {}, function () {}, function () {}], + execute: function () { + + // nested + module.import('./generated-existing.js'); + module.import('./direct-relative-external'); + module.import('to-indirect-relative-external'); + module.import('direct-absolute-external'); + module.import('to-indirect-absolute-external'); + + //main + module.import('./generated-existing.js'); + module.import('./direct-relative-external'); + module.import('to-indirect-relative-external'); + module.import('direct-absolute-external'); + module.import('to-indirect-absolute-external'); + + module.import('dynamic-direct-external' + unknown); + module.import('to-dynamic-indirect-external'); + module.import('./generated-existing.js'); + module.import('my' + 'replacement'); + + } + }; +}); diff --git a/test/chunking-form/samples/resolve-dynamic-import/existing.js b/test/chunking-form/samples/resolve-dynamic-import/existing.js new file mode 100644 index 00000000000..29aa16bd444 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/existing.js @@ -0,0 +1 @@ +export const value = 'existing'; diff --git a/test/chunking-form/samples/resolve-dynamic-import/main.js b/test/chunking-form/samples/resolve-dynamic-import/main.js new file mode 100644 index 00000000000..dd732190f3f --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/main.js @@ -0,0 +1,19 @@ +import './nested/nested.js'; + +import 'existing-name'; +import './direct-relative-external'; +import './indirect-relative-external'; +import 'direct-absolute-external'; +import 'indirect-absolute-external'; + +//main +import(`existing-name`); +import('./direct-relative-external'); +import('./indirect-relative-external'); +import('direct-absolute-external'); +import('indirect-absolute-external'); + +import('dynamic-direct-external' + unknown); +import('dynamic-indirect-external' + unknown); +import('dynamic-indirect-existing' + unknown); +import('dynamic-replaced' + unknown); diff --git a/test/chunking-form/samples/resolve-dynamic-import/nested/nested.js b/test/chunking-form/samples/resolve-dynamic-import/nested/nested.js new file mode 100644 index 00000000000..57cf6733ae8 --- /dev/null +++ b/test/chunking-form/samples/resolve-dynamic-import/nested/nested.js @@ -0,0 +1,6 @@ +// nested +import('existing-name'); +import('../direct-relative-external'); +import('../indirect-relative-external'); +import('direct-absolute-external'); +import('indirect-absolute-external'); diff --git a/test/form/samples/resolve-external-dynamic-imports/_config.js b/test/form/samples/resolve-external-dynamic-imports/_config.js index f8f2eb0bd1c..3349408669e 100644 --- a/test/form/samples/resolve-external-dynamic-imports/_config.js +++ b/test/form/samples/resolve-external-dynamic-imports/_config.js @@ -1,5 +1,5 @@ module.exports = { - description: 'correctly resolves ids of external dynamic imports (#2481)', + description: 'does not resolve external dynamic imports via plugins (#2481)', options: { output: { name: 'bundle' }, external(id) { diff --git a/test/function/samples/check-resolve-for-entry/_config.js b/test/function/samples/check-resolve-for-entry/_config.js index 492041a77f1..88ef2dd83be 100644 --- a/test/function/samples/check-resolve-for-entry/_config.js +++ b/test/function/samples/check-resolve-for-entry/_config.js @@ -1,10 +1,10 @@ module.exports = { description: 'checks that entry is resolved', options: { - input: '/not/a/path/that/actually/really/exists' + input: 'not/a/path/that/actually/really/exists' }, error: { code: 'UNRESOLVED_ENTRY', - message: 'Could not resolve entry (/not/a/path/that/actually/really/exists)' + message: 'Could not resolve entry module (not/a/path/that/actually/really/exists).' } }; diff --git a/test/function/samples/compact/main.js b/test/function/samples/compact/main.js index c094ee1ff4f..6ecb287fb92 100644 --- a/test/function/samples/compact/main.js +++ b/test/function/samples/compact/main.js @@ -1,10 +1,12 @@ import x from 'external'; import * as self from './main.js'; -console.log(self && self['de' + 'fault']); -export default function foo () { - console.log( x ); + +assert.equal(self && self['de' + 'fault'](), 42); + +export default function foo() { + return x; } import('./main.js').then(self => { - console.log(self && self['de' + 'fault']); + assert.equal(self && self['de' + 'fault'](), 42); }); diff --git a/test/function/samples/consistent-renaming-e/a.js b/test/function/samples/consistent-renaming-e/a.js index c58a637a31e..3de5b435d72 100644 --- a/test/function/samples/consistent-renaming-e/a.js +++ b/test/function/samples/consistent-renaming-e/a.js @@ -4,4 +4,4 @@ function c () { console.log( 'main/c' ); } export default function a () { return 'EH? ' + b(); -} \ No newline at end of file +} diff --git a/test/function/samples/consistent-renaming-e/b.js b/test/function/samples/consistent-renaming-e/b.js index b9f1a98ea9f..ac7a12e4e33 100644 --- a/test/function/samples/consistent-renaming-e/b.js +++ b/test/function/samples/consistent-renaming-e/b.js @@ -2,4 +2,4 @@ function c () { console.log( 'a/c' ); } export default function b () { return 42; -} \ No newline at end of file +} diff --git a/test/function/samples/context-resolve-id/_config.js b/test/function/samples/context-resolve-id/_config.js new file mode 100644 index 00000000000..cef41520d15 --- /dev/null +++ b/test/function/samples/context-resolve-id/_config.js @@ -0,0 +1,73 @@ +const path = require('path'); +const assert = require('assert'); + +module.exports = { + description: 'correctly returns string or null for the context resolveId helper', + context: { + require(id) { + switch (id) { + case 'external-name': + return { value: 'external name' }; + case 'external-object': + return { value: 'external object' }; + case 'resolveto-unresolved': + return { value: 'unresolved' }; + default: + throw new Error(`Unexpected import ${id}`); + } + } + }, + warnings(warnings) { + assert.strictEqual(warnings.length, 1); + assert.strictEqual(warnings[0].code, 'UNRESOLVED_IMPORT'); + }, + options: { + plugins: [ + { + resolveId(id, importer) { + if (id.startsWith('resolveto-')) { + const resolutionId = id.slice('resolveto-'.length); + return this.resolveId(resolutionId, importer).then(resolvedId => { + if (!resolvedId) { + assert.strictEqual(resolutionId, 'unresolved'); + assert.strictEqual(resolvedId, null); + } else { + if (typeof resolvedId !== 'string') { + throw new Error( + `Only valid resolveId return types are string and null, found ${typeof resolvedId} ${JSON.stringify( + resolvedId + )}` + ); + } + return { + id: resolvedId, + external: resolvedId.startsWith('external') + }; + } + }); + } + } + }, + { + resolveId(id) { + switch (id) { + case 'object': + return { + id: path.resolve(__dirname, 'existing-object.js'), + external: false + }; + case 'external-object': + return { + id: 'external-object', + external: true + }; + case 'name': + return path.resolve(__dirname, 'existing-name.js'); + case 'external-name': + return false; + } + } + } + ] + } +}; diff --git a/test/function/samples/context-resolve-id/existing-name.js b/test/function/samples/context-resolve-id/existing-name.js new file mode 100644 index 00000000000..d7aebd0e184 --- /dev/null +++ b/test/function/samples/context-resolve-id/existing-name.js @@ -0,0 +1 @@ +export const value = 'existing name'; diff --git a/test/function/samples/context-resolve-id/existing-object.js b/test/function/samples/context-resolve-id/existing-object.js new file mode 100644 index 00000000000..fb5c62510d0 --- /dev/null +++ b/test/function/samples/context-resolve-id/existing-object.js @@ -0,0 +1 @@ +export const value = 'existing object'; diff --git a/test/function/samples/context-resolve-id/main.js b/test/function/samples/context-resolve-id/main.js new file mode 100644 index 00000000000..188a3921e2e --- /dev/null +++ b/test/function/samples/context-resolve-id/main.js @@ -0,0 +1,11 @@ +import { value as name } from 'resolveto-name'; +import { value as externalName } from 'resolveto-external-name'; +import { value as object } from 'resolveto-object'; +import { value as externalObject } from 'resolveto-external-object'; +import { value as unresolved } from 'resolveto-unresolved'; + +assert.strictEqual(externalName, 'external name'); +assert.strictEqual(externalObject, 'external object'); +assert.strictEqual(name, 'existing name'); +assert.strictEqual(object, 'existing object'); +assert.strictEqual(unresolved, 'unresolved'); diff --git a/test/function/samples/context-resolve/_config.js b/test/function/samples/context-resolve/_config.js new file mode 100644 index 00000000000..8a6d1eff991 --- /dev/null +++ b/test/function/samples/context-resolve/_config.js @@ -0,0 +1,96 @@ +const path = require('path'); +const assert = require('assert'); + +const tests = [ + { + source: './existing', + expected: { id: path.resolve(__dirname, 'existing.js'), external: false } + }, + { + source: './missing-relative', + expected: null + }, + { + source: 'missing-absolute', + expected: null + }, + { + source: './marked-directly-external-relative', + expected: { id: path.resolve(__dirname, 'marked-directly-external-relative'), external: true } + }, + { + source: './marked-external-relative', + expected: { id: path.resolve(__dirname, 'marked-external-relative'), external: true } + }, + { + source: 'marked-external-absolute', + expected: { id: 'marked-external-absolute', external: true } + }, + { + source: 'resolved-name', + expected: { id: 'resolved:resolved-name', external: false } + }, + { + source: 'resolved-false', + expected: { id: 'resolved-false', external: true } + }, + { + source: 'resolved-object', + expected: { id: 'resolved:resolved-object', external: false } + }, + { + source: 'resolved-object-non-external', + expected: { id: 'resolved:resolved-object-non-external', external: false } + }, + { + source: 'resolved-object-external', + expected: { id: 'resolved:resolved-object-external', external: true } + } +]; + +module.exports = { + description: 'returns the correct results for the context resolve helper', + options: { + external: [ + 'marked-external-absolute', + './marked-directly-external-relative', + path.resolve(__dirname, 'marked-external-relative') + ], + plugins: [ + { + resolveId(id) { + if (id === 'resolutions') { + return id; + } + }, + load(id) { + if (id === 'resolutions') { + return Promise.all( + tests.map(({ source, expected }) => + this.resolve(source, path.resolve(__dirname, 'main.js')).then(resolution => + assert.deepStrictEqual(resolution, expected) + ) + ) + ).then(result => `export default ${result.length}`); + } + } + }, + { + resolveId(id) { + switch (id) { + case 'resolved-name': + return 'resolved:resolved-name'; + case 'resolved-false': + return false; + case 'resolved-object': + return { id: 'resolved:resolved-object' }; + case 'resolved-object-non-external': + return { id: 'resolved:resolved-object-non-external', external: false }; + case 'resolved-object-external': + return { id: 'resolved:resolved-object-external', external: true }; + } + } + } + ] + } +}; diff --git a/test/function/samples/context-resolve/existing.js b/test/function/samples/context-resolve/existing.js new file mode 100644 index 00000000000..9486260537f --- /dev/null +++ b/test/function/samples/context-resolve/existing.js @@ -0,0 +1 @@ +console.log('existing'); diff --git a/test/function/samples/context-resolve/main.js b/test/function/samples/context-resolve/main.js new file mode 100644 index 00000000000..b97e429539e --- /dev/null +++ b/test/function/samples/context-resolve/main.js @@ -0,0 +1,3 @@ +import resolutions from 'resolutions'; + +assert.strictEqual(resolutions,11); diff --git a/test/function/samples/dynamic-import-not-found/_config.js b/test/function/samples/dynamic-import-not-found/_config.js new file mode 100644 index 00000000000..2f00552892b --- /dev/null +++ b/test/function/samples/dynamic-import-not-found/_config.js @@ -0,0 +1,20 @@ +module.exports = { + description: 'warns if a dynamic import is not found', + context: { + require(id) { + if (id === 'mod') { + return {}; + } + } + }, + warnings: [ + { + code: 'UNRESOLVED_IMPORT', + importer: 'main.js', + message: + "'mod' is imported by main.js, but could not be resolved – treating it as an external dependency", + source: 'mod', + url: 'https://rollupjs.org/guide/en#warning-treating-module-as-external-dependency' + } + ] +}; diff --git a/test/function/samples/dynamic-import-not-found/main.js b/test/function/samples/dynamic-import-not-found/main.js new file mode 100644 index 00000000000..9a1c5d2d166 --- /dev/null +++ b/test/function/samples/dynamic-import-not-found/main.js @@ -0,0 +1 @@ +import('mod'); diff --git a/test/function/samples/dynamic-import-relative-not-found/_config.js b/test/function/samples/dynamic-import-relative-not-found/_config.js new file mode 100644 index 00000000000..fa9cf8e9d04 --- /dev/null +++ b/test/function/samples/dynamic-import-relative-not-found/_config.js @@ -0,0 +1,7 @@ +module.exports = { + description: 'throws if a dynamic relative import is not found', + error: { + code: 'UNRESOLVED_IMPORT', + message: `Could not resolve './mod' from main.js` + } +}; diff --git a/test/function/samples/dynamic-import-relative-not-found/main.js b/test/function/samples/dynamic-import-relative-not-found/main.js new file mode 100644 index 00000000000..f9be6719428 --- /dev/null +++ b/test/function/samples/dynamic-import-relative-not-found/main.js @@ -0,0 +1 @@ +import('./mod'); diff --git a/test/function/samples/emit-chunk/chunk-not-found/_config.js b/test/function/samples/emit-chunk/chunk-not-found/_config.js index 46e17ecb5ee..0d85644457d 100644 --- a/test/function/samples/emit-chunk/chunk-not-found/_config.js +++ b/test/function/samples/emit-chunk/chunk-not-found/_config.js @@ -10,6 +10,6 @@ module.exports = { }, error: { code: 'UNRESOLVED_ENTRY', - message: 'Could not resolve entry (not-found.js)' + message: 'Could not resolve entry module (not-found.js).' } }; diff --git a/test/function/samples/external-entry-point-object/_config.js b/test/function/samples/external-entry-point-object/_config.js new file mode 100644 index 00000000000..5f27f7b99ac --- /dev/null +++ b/test/function/samples/external-entry-point-object/_config.js @@ -0,0 +1,14 @@ +module.exports = { + description: 'throws for entry points that are resolved as an external object by plugins', + options: { + plugins: { + resolveId(id) { + return { id, external: true }; + } + } + }, + error: { + code: 'UNRESOLVED_ENTRY', + message: `Entry module cannot be external (main.js).` + } +}; diff --git a/test/function/samples/external-entry-point-object/foo.js b/test/function/samples/external-entry-point-object/foo.js new file mode 100644 index 00000000000..14d0105c721 --- /dev/null +++ b/test/function/samples/external-entry-point-object/foo.js @@ -0,0 +1,3 @@ +export var foo = function () { + return 42; +} diff --git a/test/function/samples/external-entry-point-object/main.js b/test/function/samples/external-entry-point-object/main.js new file mode 100644 index 00000000000..2a031e5db48 --- /dev/null +++ b/test/function/samples/external-entry-point-object/main.js @@ -0,0 +1,7 @@ +import { foo } from './foo.js'; + +(function bar() { + assert.ok( true ); +})(); + +assert.equal( foo(), 42 ); diff --git a/test/function/samples/external-entry-point/_config.js b/test/function/samples/external-entry-point/_config.js new file mode 100644 index 00000000000..ce44d387343 --- /dev/null +++ b/test/function/samples/external-entry-point/_config.js @@ -0,0 +1,14 @@ +module.exports = { + description: 'throws for entry points that are resolved as false by plugins', + options: { + plugins: { + resolveId() { + return false; + } + } + }, + error: { + code: 'UNRESOLVED_ENTRY', + message: `Entry module cannot be external (main.js).` + } +}; diff --git a/test/function/samples/external-entry-point/foo.js b/test/function/samples/external-entry-point/foo.js new file mode 100644 index 00000000000..14d0105c721 --- /dev/null +++ b/test/function/samples/external-entry-point/foo.js @@ -0,0 +1,3 @@ +export var foo = function () { + return 42; +} diff --git a/test/function/samples/external-entry-point/main.js b/test/function/samples/external-entry-point/main.js new file mode 100644 index 00000000000..2a031e5db48 --- /dev/null +++ b/test/function/samples/external-entry-point/main.js @@ -0,0 +1,7 @@ +import { foo } from './foo.js'; + +(function bar() { + assert.ok( true ); +})(); + +assert.equal( foo(), 42 ); diff --git a/test/function/samples/function-directive-not-first/_config.js b/test/function/samples/function-directive-not-first/_config.js index 53338e3ef8b..40d9e5d0ae5 100644 --- a/test/function/samples/function-directive-not-first/_config.js +++ b/test/function/samples/function-directive-not-first/_config.js @@ -1,9 +1,8 @@ const assert = require('assert'); module.exports = { - description: "should delete use asm from function body if it's not first expression", + description: 'should delete use asm from function body if it is not the first expression', code(code) { - console.log(code); assert.equal(code.indexOf('use asm'), -1); } }; diff --git a/test/function/samples/handle-labels-inside-functions/main.js b/test/function/samples/handle-labels-inside-functions/main.js index 1c66d5c71e7..d3492626259 100644 --- a/test/function/samples/handle-labels-inside-functions/main.js +++ b/test/function/samples/handle-labels-inside-functions/main.js @@ -4,7 +4,7 @@ function loopWithLabel () { if ( Math.random() < 0.5 ) { break label2; } - console.log( 'loop' ); + assert.equal(42, 42); } } } diff --git a/test/function/samples/keep-used-imports-from-pure-external-modules/_config.js b/test/function/samples/keep-used-imports-from-pure-external-modules/_config.js index 7f5416a3f16..a085f36b0fa 100644 --- a/test/function/samples/keep-used-imports-from-pure-external-modules/_config.js +++ b/test/function/samples/keep-used-imports-from-pure-external-modules/_config.js @@ -1,3 +1,5 @@ +const assert = require('assert'); + module.exports = { description: 'imports from pure external modules that are used should not be omitted', options: { @@ -8,7 +10,7 @@ module.exports = { }, context: { require: id => { - if (id === 'warning') return arg => console.log(arg); + if (id === 'warning') return arg => assert.equal(arg, 'hi'); throw new Error('Unexpected import', id); } } diff --git a/test/function/samples/member-expression-assignment-in-function/main.js b/test/function/samples/member-expression-assignment-in-function/main.js index f627721f445..8b4df3eca22 100644 --- a/test/function/samples/member-expression-assignment-in-function/main.js +++ b/test/function/samples/member-expression-assignment-in-function/main.js @@ -5,5 +5,4 @@ function set(key, value) { foo[key] = value; } set("bar", 2); set("qux", 3); -console.log(foo); - +assert.deepStrictEqual(foo, { bar: 2, qux: 3 }); diff --git a/test/function/samples/module-sort-order/c.js b/test/function/samples/module-sort-order/c.js index 0bc6148de14..4d7dba907ab 100644 --- a/test/function/samples/module-sort-order/c.js +++ b/test/function/samples/module-sort-order/c.js @@ -1,5 +1,5 @@ import { b } from './b'; -export var c = function () { - console.log('c'); +export var c = function() { + assert.equal(42, 42); }; diff --git a/test/function/samples/namespacing-collisions-2/Something.js b/test/function/samples/namespacing-collisions-2/Something.js index 64cbdcacd9d..7ee71ac82c6 100644 --- a/test/function/samples/namespacing-collisions-2/Something.js +++ b/test/function/samples/namespacing-collisions-2/Something.js @@ -1,6 +1,6 @@ import * as Material from './Material'; export function Something() { - console.log(Material); + assert.strictEqual(Material.Material(), 'Material'); return 'Something'; -} \ No newline at end of file +} diff --git a/test/function/samples/namespacing-collisions-2/SomethingAgain.js b/test/function/samples/namespacing-collisions-2/SomethingAgain.js index 1efaca71d0b..c39d94a3b57 100644 --- a/test/function/samples/namespacing-collisions-2/SomethingAgain.js +++ b/test/function/samples/namespacing-collisions-2/SomethingAgain.js @@ -1,6 +1,6 @@ import * as Material from './MaterialAgain'; export function SomethingAgain() { - console.log(Material); + assert.strictEqual(Material.MaterialAgain(), 'MaterialAgain'); return 'SomethingAgain'; -} \ No newline at end of file +} diff --git a/test/function/samples/namespacing-collisions/Something.js b/test/function/samples/namespacing-collisions/Something.js index 64cbdcacd9d..7ee71ac82c6 100644 --- a/test/function/samples/namespacing-collisions/Something.js +++ b/test/function/samples/namespacing-collisions/Something.js @@ -1,6 +1,6 @@ import * as Material from './Material'; export function Something() { - console.log(Material); + assert.strictEqual(Material.Material(), 'Material'); return 'Something'; -} \ No newline at end of file +} diff --git a/test/function/samples/namespacing-collisions/_config.js b/test/function/samples/namespacing-collisions/_config.js index 86daaa840f4..3469dcf3dd0 100644 --- a/test/function/samples/namespacing-collisions/_config.js +++ b/test/function/samples/namespacing-collisions/_config.js @@ -3,6 +3,6 @@ const assert = require('assert'); module.exports = { description: 'correctly namespaces when using * exports (#910)', exports(exports) { - assert.deepEqual(exports, ['Material', 'Something']); + assert.deepStrictEqual(exports, ['Material', 'Something']); } }; diff --git a/test/function/samples/plugin-error-only-first-render-chunk/main.js b/test/function/samples/plugin-error-only-first-render-chunk/main.js index 4e2e0f51157..296d5492b00 100644 --- a/test/function/samples/plugin-error-only-first-render-chunk/main.js +++ b/test/function/samples/plugin-error-only-first-render-chunk/main.js @@ -1 +1 @@ -console.log(1); \ No newline at end of file +console.log(1); diff --git a/test/function/samples/plugin-error-only-first-transform-bundle/main.js b/test/function/samples/plugin-error-only-first-transform-bundle/main.js index 4e2e0f51157..296d5492b00 100644 --- a/test/function/samples/plugin-error-only-first-transform-bundle/main.js +++ b/test/function/samples/plugin-error-only-first-transform-bundle/main.js @@ -1 +1 @@ -console.log(1); \ No newline at end of file +console.log(1); diff --git a/test/function/samples/plugin-error-only-first-transform/main.js b/test/function/samples/plugin-error-only-first-transform/main.js index 4e2e0f51157..296d5492b00 100644 --- a/test/function/samples/plugin-error-only-first-transform/main.js +++ b/test/function/samples/plugin-error-only-first-transform/main.js @@ -1 +1 @@ -console.log(1); \ No newline at end of file +console.log(1); diff --git a/test/function/samples/side-effects-only-default-exports/_expected/amd.js b/test/function/samples/side-effects-only-default-exports/_expected/amd.js index 4718f2e6862..308b0b8c7bc 100644 --- a/test/function/samples/side-effects-only-default-exports/_expected/amd.js +++ b/test/function/samples/side-effects-only-default-exports/_expected/amd.js @@ -7,4 +7,4 @@ define(function () { 'use strict'; a(); a(); -}); \ No newline at end of file +}); diff --git a/test/function/samples/side-effects-only-default-exports/_expected/cjs.js b/test/function/samples/side-effects-only-default-exports/_expected/cjs.js index 473b57e0197..4b1f7113031 100644 --- a/test/function/samples/side-effects-only-default-exports/_expected/cjs.js +++ b/test/function/samples/side-effects-only-default-exports/_expected/cjs.js @@ -5,4 +5,4 @@ var a = () => { }; a(); -a(); \ No newline at end of file +a(); diff --git a/test/function/samples/side-effects-only-default-exports/_expected/es.js b/test/function/samples/side-effects-only-default-exports/_expected/es.js index 0415d2c05c3..c387edcca09 100644 --- a/test/function/samples/side-effects-only-default-exports/_expected/es.js +++ b/test/function/samples/side-effects-only-default-exports/_expected/es.js @@ -3,4 +3,4 @@ var a = () => { }; a(); -a(); \ No newline at end of file +a(); diff --git a/test/function/samples/side-effects-only-default-exports/_expected/iife.js b/test/function/samples/side-effects-only-default-exports/_expected/iife.js index cb9df4a40c8..46c38fba33b 100644 --- a/test/function/samples/side-effects-only-default-exports/_expected/iife.js +++ b/test/function/samples/side-effects-only-default-exports/_expected/iife.js @@ -8,4 +8,4 @@ a(); a(); -}()); \ No newline at end of file +}()); diff --git a/test/function/samples/transparent-dynamic-inlining/foo.js b/test/function/samples/transparent-dynamic-inlining/foo.js index bb5b9de3bfe..96b14ac739a 100644 --- a/test/function/samples/transparent-dynamic-inlining/foo.js +++ b/test/function/samples/transparent-dynamic-inlining/foo.js @@ -1,4 +1,4 @@ export var x = 42; -import( './main' ).then(x => { - console.log( x ); +import('./main').then(x => { + assert.deepStrictEqual(x, { y: 42 }); }); diff --git a/test/function/samples/trim-conditional-branches-in-exports/main.js b/test/function/samples/trim-conditional-branches-in-exports/main.js index 8e67e6f5b06..035aebe2b1d 100644 --- a/test/function/samples/trim-conditional-branches-in-exports/main.js +++ b/test/function/samples/trim-conditional-branches-in-exports/main.js @@ -1,2 +1,2 @@ import foo from './foo.js'; -console.log( true ? false ? foo : 0 : 1 ); +assert.equal(true ? (false ? foo : 0) : 1, 0); diff --git a/test/function/samples/try-catch-scoping/foo.js b/test/function/samples/try-catch-scoping/foo.js index 160e8eab792..79368c23255 100644 --- a/test/function/samples/try-catch-scoping/foo.js +++ b/test/function/samples/try-catch-scoping/foo.js @@ -4,4 +4,4 @@ export default function foo () { } catch ( err ) { console.log( err ); } -} \ No newline at end of file +} diff --git a/test/function/samples/uses-supplied-ast/_config.js b/test/function/samples/uses-supplied-ast/_config.js index 8f25e825129..66f80912006 100644 --- a/test/function/samples/uses-supplied-ast/_config.js +++ b/test/function/samples/uses-supplied-ast/_config.js @@ -6,9 +6,9 @@ const modules = { // the code points to './bar' but the AST points to './baz', so we // can check the AST is being used foo: { - code: "import bar from 'bar';\nexport default function foo () {\n\tconsole.log( bar );\n}", + code: "import bar from 'bar';\nexport default function foo () {\n\tassert.equal(bar, 42);\n}", ast: acorn.parse( - "import bar from 'baz';\nexport default function foo () {\n\tconsole.log( bar );\n}", + "import bar from 'baz';\nexport default function foo () {\n\tassert.equal(bar, 42);\n}", { ecmaVersion: 6, sourceType: 'module'