Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v3.0] Better sourcemap emission #4605

Merged
merged 22 commits into from Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
16b0cbb
[v3.0] Deprecate Node 12 (#4548)
lukastaegert Jul 3, 2022
8dfcd36
[v3.0] Remove actively deprecated features, show warnings for other d…
lukastaegert Jul 4, 2022
79e18b3
[v3.0] New hashing algorithm that "fixes (nearly) everything" (#4543)
lukastaegert Jul 5, 2022
465dbb4
[v3.0] Run output plugins last (#3846)
aleclarson Jul 7, 2022
4e520ca
[v3.0] Convert build scripts to ESM, update dependencies (#4558)
lukastaegert Jul 8, 2022
2942e7b
[v3.0] Better esm config file support (#4574)
lukastaegert Jul 15, 2022
2cc052b
[v3.0] Rework file name patterns when preserving modules (#4565)
lukastaegert Jul 15, 2022
ff65a10
[v3.0] Show deprecation warning for maxParallelFileReads (#4575)
lukastaegert Jul 15, 2022
116218c
[v3.0] Restructure timings (#4566)
lukastaegert Jul 15, 2022
79bed07
[v3.0] Change default for makeAbsoluteExternalsRelative (#4567)
lukastaegert Jul 15, 2022
ab391de
[v3.0] Change default for output.generatedCode.reservedNamesAsProps (…
lukastaegert Jul 15, 2022
d196046
[v3.0] Change default for preserveEntrySignatures to exports-only (#4…
lukastaegert Jul 15, 2022
0ab0b41
Port doc changes from #4572 and #4583 to 3.0 (#4592)
berniegp Jul 30, 2022
fefed10
[v3.0] Refine errors and warnings (#4579)
lukastaegert Jul 30, 2022
e5b3ba0
[v3.0] Browser build (#4593)
lukastaegert Jul 30, 2022
41906ce
[v3.0] Use named export for loadConfigFile (#4581)
lukastaegert Jul 30, 2022
b530497
3.0.0-3
lukastaegert Jul 30, 2022
4c3b1a4
Fix release script
lukastaegert Jul 30, 2022
c322542
[v3.0] Use "node:" prefix for imports of node builtins (#4596)
lukastaegert Aug 11, 2022
1e7f339
Support inline sourcemaps
lukastaegert Aug 11, 2022
6f5f74d
Emit sourcemaps as assets and add comments before generateBundle
lukastaegert Aug 13, 2022
75cf563
Merge branch 'release-3.0.0' into better-sourcemap-handling
lukastaegert Aug 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 1 addition & 12 deletions cli/run/build.ts
Expand Up @@ -5,7 +5,6 @@ import type { MergedRollupOptions } from '../../src/rollup/types';
import { bold, cyan, green } from '../../src/utils/colors';
import { errOnlyInlineSourcemapsForStdout } from '../../src/utils/error';
import relativeId from '../../src/utils/relativeId';
import { SOURCEMAPPING_URL } from '../../src/utils/sourceMappingURL';
import { handleError, stderr } from '../logging';
import type { BatchWarnings } from './batchWarnings';
import { printTimings } from './timings';
Expand Down Expand Up @@ -37,20 +36,10 @@ export default async function build(
if (output.sourcemap && output.sourcemap !== 'inline') {
handleError(errOnlyInlineSourcemapsForStdout());
}

const { output: outputs } = await bundle.generate(output);
for (const file of outputs) {
let source: string | Uint8Array;
if (file.type === 'asset') {
source = file.source;
} else {
source = file.code;
if (output.sourcemap === 'inline') {
source += `\n//# ${SOURCEMAPPING_URL}=${file.map!.toUrl()}\n`;
}
}
if (outputs.length > 1) process.stdout.write(`\n${cyan(bold(`//→ ${file.fileName}:`))}\n`);
process.stdout.write(source as Buffer);
process.stdout.write(file.type === 'asset' ? file.source : file.code);
}
if (!silent) {
warnings.flush();
Expand Down
29 changes: 2 additions & 27 deletions src/rollup/rollup.ts
Expand Up @@ -15,9 +15,8 @@ import { catchUnfinishedHookActions } from '../utils/hookActions';
import { normalizeInputOptions } from '../utils/options/normalizeInputOptions';
import { normalizeOutputOptions } from '../utils/options/normalizeOutputOptions';
import type { GenericConfigObject } from '../utils/options/options';
import { basename, dirname, resolve } from '../utils/path';
import { dirname, resolve } from '../utils/path';
import { ANONYMOUS_OUTPUT_PLUGIN_PREFIX, ANONYMOUS_PLUGIN_PREFIX } from '../utils/pluginUtils';
import { SOURCEMAPPING_URL } from '../utils/sourceMappingURL';
import { getTimings, initialiseTimers, timeEnd, timeStart } from '../utils/timers';
import type {
NormalizedInputOptions,
Expand Down Expand Up @@ -282,31 +281,7 @@ async function writeOutputFile(
// 'recursive: true' does not throw if the folder structure, or parts of it, already exist
await fs.mkdir(dirname(fileName), { recursive: true });

let writeSourceMapPromise: Promise<void> | undefined;
let source: string | Uint8Array;
if (outputFile.type === 'asset') {
source = outputFile.source;
} else {
source = outputFile.code;
if (outputOptions.sourcemap && outputFile.map) {
let url: string;
if (outputOptions.sourcemap === 'inline') {
url = outputFile.map.toUrl();
} else {
const { sourcemapBaseUrl } = outputOptions;
const sourcemapFileName = `${basename(outputFile.fileName)}.map`;
url = sourcemapBaseUrl
? new URL(sourcemapFileName, sourcemapBaseUrl).toString()
: sourcemapFileName;
writeSourceMapPromise = fs.writeFile(`${fileName}.map`, outputFile.map.toString());
}
if (outputOptions.sourcemap !== 'hidden') {
source += `//# ${SOURCEMAPPING_URL}=${url}\n`;
}
}
}

return Promise.all([fs.writeFile(fileName, source), writeSourceMapPromise]);
return fs.writeFile(fileName, outputFile.type === 'asset' ? outputFile.source : outputFile.code);
}

/**
Expand Down
38 changes: 33 additions & 5 deletions src/utils/renderChunks.ts
Expand Up @@ -19,7 +19,8 @@ import {
replacePlaceholdersWithDefaultAndGetContainedPlaceholders,
replaceSinglePlaceholder
} from './hashPlaceholders';
import { normalize, resolve } from './path';
import { basename, normalize, resolve } from './path';
import { SOURCEMAPPING_URL } from './sourceMappingURL';
import { timeEnd, timeStart } from './timers';

interface HashResult {
Expand Down Expand Up @@ -70,7 +71,9 @@ export async function renderChunks(
renderedChunksByPlaceholder,
hashesByPlaceholder,
outputBundle,
nonHashedChunksWithPlaceholders
nonHashedChunksWithPlaceholders,
pluginDriver,
outputOptions
);

timeEnd('transform chunks', 2);
Expand Down Expand Up @@ -286,20 +289,45 @@ function addChunksToBundle(
renderedChunksByPlaceholder: Map<string, RenderedChunkWithPlaceholders>,
hashesByPlaceholder: Map<string, string>,
outputBundle: OutputBundleWithPlaceholders,
nonHashedChunksWithPlaceholders: RenderedChunkWithPlaceholders[]
nonHashedChunksWithPlaceholders: RenderedChunkWithPlaceholders[],
pluginDriver: PluginDriver,
options: NormalizedOutputOptions
) {
for (const { chunk, code, fileName, map } of renderedChunksByPlaceholder.values()) {
const updatedCode = replacePlaceholders(code, hashesByPlaceholder);
let updatedCode = replacePlaceholders(code, hashesByPlaceholder);
const finalFileName = replacePlaceholders(fileName, hashesByPlaceholder);
if (map) {
map.file = replacePlaceholders(map.file, hashesByPlaceholder);
updatedCode += emitSourceMapAndGetComment(finalFileName, map, pluginDriver, options);
}
outputBundle[finalFileName] = chunk.generateOutputChunk(updatedCode, map, hashesByPlaceholder);
}
for (const { chunk, code, fileName, map } of nonHashedChunksWithPlaceholders) {
const updatedCode = hashesByPlaceholder.size
let updatedCode = hashesByPlaceholder.size
? replacePlaceholders(code, hashesByPlaceholder)
: code;
if (map) {
updatedCode += emitSourceMapAndGetComment(fileName, map, pluginDriver, options);
}
outputBundle[fileName] = chunk.generateOutputChunk(updatedCode, map, hashesByPlaceholder);
}
}

function emitSourceMapAndGetComment(
fileName: string,
map: SourceMap,
pluginDriver: PluginDriver,
{ sourcemap, sourcemapBaseUrl }: NormalizedOutputOptions
) {
let url: string;
if (sourcemap === 'inline') {
url = map.toUrl();
} else {
const sourcemapFileName = `${basename(fileName)}.map`;
url = sourcemapBaseUrl
? new URL(sourcemapFileName, sourcemapBaseUrl).toString()
: sourcemapFileName;
pluginDriver.emitFile({ fileName: `${fileName}.map`, source: map.toString(), type: 'asset' });
}
return sourcemap === 'hidden' ? '' : `//# ${SOURCEMAPPING_URL}=${url}\n`;
}
1 change: 0 additions & 1 deletion test/cli/samples/stdout-single-input/_expected.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions test/function/samples/sourcemap-inline-generatebundle/_config.js
@@ -0,0 +1,26 @@
const assert = require('assert');

module.exports = {
description: 'includes inline sourcemap comments in generateBundle hook',
options: {
plugins: [
{
name: 'test',
generateBundle(options, bundle) {
assert.deepStrictEqual(Object.keys(bundle), ['main.js']);
assert.strictEqual(
bundle['main.js'].code,
`'use strict';

var main = 42;

module.exports = main;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibWFpbi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZGVmYXVsdCA0MjtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLFdBQWUsRUFBRTs7OzsifQ==
`
);
}
}
],
output: { sourcemap: 'inline' }
}
};
@@ -0,0 +1 @@
export default 42;
33 changes: 33 additions & 0 deletions test/function/samples/sourcemap-true-generatebundle/_config.js
@@ -0,0 +1,33 @@
const assert = require('assert');

module.exports = {
description: 'emits sourcemaps before generateBundle hook',
options: {
plugins: [
{
name: 'test',
generateBundle(options, bundle) {
assert.deepStrictEqual(Object.keys(bundle), ['main.js', 'main.js.map']);
assert.strictEqual(
bundle['main.js'].code,
`'use strict';
var main = 42;
module.exports = main;
//# sourceMappingURL=main.js.map
`
);
assert.deepStrictEqual(bundle['main.js.map'], {
fileName: 'main.js.map',
name: undefined,
source:
'{"version":3,"file":"main.js","sources":["main.js"],"sourcesContent":["export default 42;\\n"],"names":[],"mappings":";;AAAA,WAAe,EAAE;;;;"}',
type: 'asset'
});
}
}
],
output: { sourcemap: true }
}
};
@@ -0,0 +1 @@
export default 42;
Expand Up @@ -3,6 +3,6 @@ const assert = require('assert');
module.exports = {
description: 'removes sourcemap comments',
async test(code) {
assert.ok(!code.includes('sourceMappingURL'));
assert.ok(!code.includes('sourceMappingURL=main.js.map'));
}
};
Expand Up @@ -3,6 +3,6 @@ const assert = require('assert');
module.exports = {
description: 'removes existing inline sourcemaps',
async test(code) {
assert.ok(!code.includes('sourceMappingURL'));
assert.ok(!code.includes('sourceMappingURL=data'));
}
};