diff --git a/src/Graph.ts b/src/Graph.ts index 4beda3c3047..8bf31e0d787 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -45,6 +45,10 @@ function makeOnwarn() { }; } +function normalizeRelativeExternalId(importee: string, source: string) { + return isRelative(source) ? resolve(importee, '..', source) : source; +} + export default class Graph { acornOptions: acorn.Options; acornParser: typeof acorn.Parser; @@ -637,42 +641,56 @@ export default class Graph { module: Module, source: string ): ResolvedId { + let id = ''; + let external = false; if (resolveIdResult) { if (typeof resolveIdResult === 'object') { - return resolveIdResult; + id = resolveIdResult.id; + if (resolveIdResult.external) { + external = true; + } + } else { + id = resolveIdResult; + if (this.isExternal(id, module.id, true)) { + external = true; + } } - return { id: resolveIdResult, external: this.isExternal(resolveIdResult, module.id, true) }; - } - const externalId = isRelative(source) ? resolve(module.id, '..', source) : source; - if (resolveIdResult !== false && !this.isExternal(externalId, module.id, true)) { - if (isRelative(source)) { - error({ + if (external) { + id = normalizeRelativeExternalId(module.id, 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.warn({ code: 'UNRESOLVED_IMPORT', - message: `Could not resolve '${source}' from ${relativeId(module.id)}` + 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' }); } - this.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' - }); } - return { id: externalId, external: true }; + return { id, external }; } - private resolveAndFetchDependency(module: Module, source: string) { + private resolveAndFetchDependency(module: Module, source: string): Promise { return Promise.resolve( module.resolvedIds[source] || - (this.isExternal(source, module.id, false) - ? { id: source, external: true } - : this.pluginDriver - .hookFirst('resolveId', [source, module.id]) - .then(result => this.normalizeResolveIdResult(result, module, source))) - ).then((resolvedId: ResolvedId) => { + Promise.resolve( + this.isExternal(source, module.id, false) + ? { id: source, external: true } + : this.pluginDriver.hookFirst('resolveId', [source, module.id]) + ).then(result => this.normalizeResolveIdResult(result, module, source)) + ).then(resolvedId => { module.resolvedIds[source] = resolvedId; if (resolvedId.external) { if (!this.moduleById.has(resolvedId.id)) { diff --git a/test/form/samples/relative-external-ids/_config.js b/test/form/samples/relative-external-ids/_config.js new file mode 100644 index 00000000000..e9a83810940 --- /dev/null +++ b/test/form/samples/relative-external-ids/_config.js @@ -0,0 +1,37 @@ +const path = require('path'); + +module.exports = { + description: 'relative external ids are absolutely resolved', + options: { + external(id) { + switch (id) { + case './optionDirect.js': + return true; + case './optionDirectNested.js': + return true; + case path.resolve(__dirname, 'optionIndirect.js'): + return true; + case path.resolve(__dirname, 'nested', 'optionIndirectNested.js'): + return true; + default: + return false; + } + }, + plugins: { + resolveId(id) { + switch (id) { + case './hook.js': + return false; + case './hookNested.js': + return false; + case 'resolved': + return { id: './resolved.js', external: true }; + case 'resolvedNested': + return { id: './resolvedNested.js', external: true }; + default: + return null; + } + } + } + } +}; diff --git a/test/form/samples/relative-external-ids/_expected.js b/test/form/samples/relative-external-ids/_expected.js new file mode 100644 index 00000000000..d035d8a8fe9 --- /dev/null +++ b/test/form/samples/relative-external-ids/_expected.js @@ -0,0 +1,8 @@ +import './optionDirect.js'; +import './optionIndirect.js'; +import './hook.js'; +import './resolved.js'; +import './nested/optionDirectNested.js'; +import './nested/optionIndirectNested.js'; +import './nested/hookNested.js'; +import './nested/resolvedNested.js'; diff --git a/test/form/samples/relative-external-ids/main.js b/test/form/samples/relative-external-ids/main.js new file mode 100644 index 00000000000..7e102a0ae04 --- /dev/null +++ b/test/form/samples/relative-external-ids/main.js @@ -0,0 +1,6 @@ +import './optionDirect.js'; +import './optionIndirect.js'; +import './hook.js'; +import 'resolved'; + +import './nested/nested'; diff --git a/test/form/samples/relative-external-ids/nested/nested.js b/test/form/samples/relative-external-ids/nested/nested.js new file mode 100644 index 00000000000..ae1abdf16b1 --- /dev/null +++ b/test/form/samples/relative-external-ids/nested/nested.js @@ -0,0 +1,4 @@ +import './optionDirectNested.js'; +import './optionIndirectNested.js'; +import './hookNested.js'; +import 'resolvedNested';