diff --git a/docs/999-big-list-of-options.md b/docs/999-big-list-of-options.md
index 38736b1fcf7..6bff411623b 100755
--- a/docs/999-big-list-of-options.md
+++ b/docs/999-big-list-of-options.md
@@ -614,6 +614,31 @@ Default: `true`
Whether to `Object.freeze()` namespace import objects (i.e. `import * as namespaceImportObject from...`) that are accessed dynamically.
+#### output.importMetaUrl
+Type: `((chunkId: string, moduleId: string) => string)`
+
+This allows the user to configure how Rollup handles `import.meta.url`. In ES modules, `import.meta.url` returns the URL of the current module, e.g. `http://server.net/bundle.js` for browsers or `file:///path/to/bundle.js` in Node.
+
+By default for formats other than ES modules, Rollup replaces `import.meta.url` with code that attempts to match this behaviour by returning the dynamic URL of the current chunk. Note that all formats except CommonJS and UMD assume that they run in a browser environment where `URL` and `document` are available.
+
+ This behaviour can be customized by supplying a function, which will replace `import.meta.url` for all formats:
+
+```javascript
+// rollup.config.js
+export default {
+ ...,
+ output: {
+ ...,
+
+ // this will use the original module id when resolving import.meta.url
+ importMetaUrl(chunkId, moduleId) {
+ return `"${moduleId}"`;
+ }
+ }
+};
+
+```
+
#### output.indent
Type: `boolean | string`
CLI: `--indent`/`--no-indent`
@@ -621,7 +646,7 @@ Default: `true`
The indent string to use, for formats that require code to be indented (`amd`, `iife`, `umd`, `system`). Can also be `false` (no indent), or `true` (the default – auto-indent)
-```js
+```javascript
// rollup.config.js
export default {
...,
diff --git a/src/Chunk.ts b/src/Chunk.ts
index 4601b6d133d..144dc064997 100644
--- a/src/Chunk.ts
+++ b/src/Chunk.ts
@@ -800,7 +800,9 @@ export default class Chunk {
const module = this.orderedModules[i];
const code = this.renderedModuleSources[i];
for (const importMeta of module.importMetas) {
- if (importMeta.renderFinalMechanism(code, this.id, options.format)) usesMechanism = true;
+ if (importMeta.renderFinalMechanism(code, this.id, options.format, options.importMetaUrl)) {
+ usesMechanism = true;
+ }
}
}
return usesMechanism;
diff --git a/src/ast/nodes/MetaProperty.ts b/src/ast/nodes/MetaProperty.ts
index 233aaae0d16..b49f5f732a1 100644
--- a/src/ast/nodes/MetaProperty.ts
+++ b/src/ast/nodes/MetaProperty.ts
@@ -22,6 +22,7 @@ const importMetaUrlMechanisms: Record string> = {
`(require('u' + 'rl').URL)`
)} : ${getUrlFromDocument(chunkId)})`,
iife: chunkId => getUrlFromDocument(chunkId),
+ system: () => `module.meta.url`,
umd: chunkId =>
`(typeof document === 'undefined' ? ${getResolveUrl(
`'file:' + __filename`,
@@ -68,12 +69,15 @@ export default class MetaProperty extends NodeBase {
super.render(code, options);
}
- renderFinalMechanism(code: MagicString, chunkId: string, format: string): boolean {
- if (!this.rendered) return false;
+ renderFinalMechanism(
+ code: MagicString,
+ chunkId: string,
+ format: string,
+ renderImportMetaUrl: ((chunkId: string, moduleId: string) => string) | void
+ ): boolean {
+ if (!this.included || !(this.parent instanceof MemberExpression)) return false;
- if (this.parent instanceof MemberExpression === false) return false;
-
- const parent = this.parent;
+ const parent = this.parent;
let importMetaProperty: string;
if (parent.property instanceof Identifier) importMetaProperty = parent.property.name;
@@ -89,12 +93,11 @@ export default class MetaProperty extends NodeBase {
return true;
}
- if (format === 'system') {
- code.overwrite(this.meta.start, this.meta.end, 'module');
- } else if (importMetaProperty === 'url') {
- const importMetaUrlMechanism = importMetaUrlMechanisms[format];
- if (importMetaUrlMechanism)
- code.overwrite(parent.start, parent.end, importMetaUrlMechanism(chunkId));
+ if (importMetaProperty === 'url') {
+ const getImportMetaUrl = renderImportMetaUrl || importMetaUrlMechanisms[format];
+ if (getImportMetaUrl) {
+ code.overwrite(parent.start, parent.end, getImportMetaUrl(chunkId, this.context.module.id));
+ }
return true;
}
diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts
index 2e64f739804..529e4a14ca7 100644
--- a/src/rollup/types.d.ts
+++ b/src/rollup/types.d.ts
@@ -315,6 +315,7 @@ export interface OutputOptions {
format?: ModuleFormat;
freeze?: boolean;
globals?: GlobalsOption;
+ importMetaUrl?: (chunkId: string, moduleId: string) => string;
indent?: boolean;
interop?: boolean;
intro?: string | (() => string | Promise);
diff --git a/src/utils/mergeOptions.ts b/src/utils/mergeOptions.ts
index 8f8c2629a98..8c6bd3d4856 100644
--- a/src/utils/mergeOptions.ts
+++ b/src/utils/mergeOptions.ts
@@ -248,6 +248,7 @@ function getOutputOptions(
format: format === 'esm' ? 'es' : format,
freeze: getOption('freeze', true),
globals: getOption('globals'),
+ importMetaUrl: getOption('importMetaUrl'),
indent: getOption('indent', true),
interop: getOption('interop', true),
intro: getOption('intro'),
diff --git a/test/form/samples/configure-import-meta-url/_config.js b/test/form/samples/configure-import-meta-url/_config.js
new file mode 100644
index 00000000000..8b37dddd4fa
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_config.js
@@ -0,0 +1,13 @@
+module.exports = {
+ description: 'allows to configure import.meta.url',
+ options: {
+ output: {
+ importMetaUrl(chunkId, moduleId) {
+ return `'${chunkId}/${moduleId
+ .split('/')
+ .slice(-2)
+ .join('/')}'`;
+ }
+ }
+ }
+};
diff --git a/test/form/samples/configure-import-meta-url/_expected/amd.js b/test/form/samples/configure-import-meta-url/_expected/amd.js
new file mode 100644
index 00000000000..a05f2631fd5
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/amd.js
@@ -0,0 +1,5 @@
+define(['module'], function (module) { 'use strict';
+
+ console.log('amd.js/configure-import-meta-url/main.js');
+
+});
diff --git a/test/form/samples/configure-import-meta-url/_expected/cjs.js b/test/form/samples/configure-import-meta-url/_expected/cjs.js
new file mode 100644
index 00000000000..a73c255c05e
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/cjs.js
@@ -0,0 +1,3 @@
+'use strict';
+
+console.log('cjs.js/configure-import-meta-url/main.js');
diff --git a/test/form/samples/configure-import-meta-url/_expected/es.js b/test/form/samples/configure-import-meta-url/_expected/es.js
new file mode 100644
index 00000000000..a71014898e3
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/es.js
@@ -0,0 +1 @@
+console.log('es.js/configure-import-meta-url/main.js');
diff --git a/test/form/samples/configure-import-meta-url/_expected/iife.js b/test/form/samples/configure-import-meta-url/_expected/iife.js
new file mode 100644
index 00000000000..d4aff63d317
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/iife.js
@@ -0,0 +1,6 @@
+(function () {
+ 'use strict';
+
+ console.log('iife.js/configure-import-meta-url/main.js');
+
+}());
diff --git a/test/form/samples/configure-import-meta-url/_expected/system.js b/test/form/samples/configure-import-meta-url/_expected/system.js
new file mode 100644
index 00000000000..f0105ea8de8
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/system.js
@@ -0,0 +1,10 @@
+System.register([], function (exports, module) {
+ 'use strict';
+ return {
+ execute: function () {
+
+ console.log('system.js/configure-import-meta-url/main.js');
+
+ }
+ };
+});
diff --git a/test/form/samples/configure-import-meta-url/_expected/umd.js b/test/form/samples/configure-import-meta-url/_expected/umd.js
new file mode 100644
index 00000000000..fb16fd659d9
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/_expected/umd.js
@@ -0,0 +1,8 @@
+(function (factory) {
+ typeof define === 'function' && define.amd ? define(factory) :
+ factory();
+}(function () { 'use strict';
+
+ console.log('umd.js/configure-import-meta-url/main.js');
+
+}));
diff --git a/test/form/samples/configure-import-meta-url/main.js b/test/form/samples/configure-import-meta-url/main.js
new file mode 100644
index 00000000000..d9536a69b3f
--- /dev/null
+++ b/test/form/samples/configure-import-meta-url/main.js
@@ -0,0 +1 @@
+console.log(import.meta.url);
diff --git a/test/misc/optionList.js b/test/misc/optionList.js
index ab34fa25c8c..57b7a6cb097 100644
--- a/test/misc/optionList.js
+++ b/test/misc/optionList.js
@@ -1,3 +1,3 @@
exports.input = 'acorn, acornInjectPlugins, cache, chunkGroupingSize, context, experimentalCacheExpiry, experimentalOptimizeChunks, experimentalTopLevelAwait, external, inlineDynamicImports, input, manualChunks, moduleContext, onwarn, perf, plugins, preserveModules, preserveSymlinks, shimMissingExports, treeshake, watch';
-exports.flags = 'acorn, acornInjectPlugins, amd, assetFileNames, banner, c, cache, chunkFileNames, chunkGroupingSize, compact, config, context, d, dir, dynamicImportFunction, e, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalOptimizeChunks, experimentalTopLevelAwait, exports, extend, external, f, file, footer, format, freeze, g, globals, h, i, indent, inlineDynamicImports, input, interop, intro, m, manualChunks, moduleContext, n, name, namespaceToStringTag, noConflict, o, onwarn, outro, paths, perf, plugins, preferConst, preserveModules, preserveSymlinks, shimMissingExports, silent, sourcemap, sourcemapExcludeSources, sourcemapFile, strict, treeshake, v, w, watch';
-exports.output = 'amd, assetFileNames, banner, chunkFileNames, compact, dir, dynamicImportFunction, entryFileNames, esModule, exports, extend, file, footer, format, freeze, globals, indent, interop, intro, name, namespaceToStringTag, noConflict, outro, paths, preferConst, sourcemap, sourcemapExcludeSources, sourcemapFile, sourcemapPathTransform, strict';
+exports.flags = 'acorn, acornInjectPlugins, amd, assetFileNames, banner, c, cache, chunkFileNames, chunkGroupingSize, compact, config, context, d, dir, dynamicImportFunction, e, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalOptimizeChunks, experimentalTopLevelAwait, exports, extend, external, f, file, footer, format, freeze, g, globals, h, i, importMetaUrl, indent, inlineDynamicImports, input, interop, intro, m, manualChunks, moduleContext, n, name, namespaceToStringTag, noConflict, o, onwarn, outro, paths, perf, plugins, preferConst, preserveModules, preserveSymlinks, shimMissingExports, silent, sourcemap, sourcemapExcludeSources, sourcemapFile, strict, treeshake, v, w, watch';
+exports.output = 'amd, assetFileNames, banner, chunkFileNames, compact, dir, dynamicImportFunction, entryFileNames, esModule, exports, extend, file, footer, format, freeze, globals, importMetaUrl, indent, interop, intro, name, namespaceToStringTag, noConflict, outro, paths, preferConst, sourcemap, sourcemapExcludeSources, sourcemapFile, sourcemapPathTransform, strict';