mirror of https://github.com/microsoft/vscode.git
esm - better content mapper to address sourcemaps (#230476)
This commit is contained in:
parent
fe391be9f0
commit
9bd60d090a
|
@ -138,7 +138,16 @@ steps:
|
|||
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
|
||||
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
|
||||
node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.main.js.map
|
||||
displayName: Upload sourcemaps (Web)
|
||||
displayName: Upload sourcemaps (Web Main)
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
AZURE_STORAGE_ACCOUNT="vscodeweb" \
|
||||
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
|
||||
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
|
||||
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
|
||||
node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.main.internal.js.map
|
||||
displayName: Upload sourcemaps (Web Internal)
|
||||
|
||||
# upload only the workbench.web.main.js source maps because
|
||||
# we just compiled these bits in the previous step and the
|
||||
|
|
|
@ -85,77 +85,31 @@ const vscodeWebEntryPoints = [
|
|||
buildfile.entrypoint('vs/workbench/workbench.web.main.internal') // TODO@esm remove line when we stop supporting web-amd-esm-bridge
|
||||
].flat();
|
||||
|
||||
/**
|
||||
* @param {object} product The parsed product.json file contents
|
||||
*/
|
||||
const createVSCodeWebProductConfigurationPatcher = (product) => {
|
||||
/**
|
||||
* @param content {string} The contents of the file
|
||||
* @param path {string} The absolute file path, always using `/`, even on Windows
|
||||
*/
|
||||
const result = (content, path) => {
|
||||
// (1) Patch product configuration
|
||||
if (path.endsWith('vs/platform/product/common/product.js')) {
|
||||
const productConfiguration = JSON.stringify({
|
||||
...product,
|
||||
version,
|
||||
commit,
|
||||
date: readISODate('out-build')
|
||||
});
|
||||
return content.replace('/*BUILD->INSERT_PRODUCT_CONFIGURATION*/', () => productConfiguration.substr(1, productConfiguration.length - 2) /* without { and }*/);
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param extensionsRoot {string} The location where extension will be read from
|
||||
*/
|
||||
const createVSCodeWebBuiltinExtensionsPatcher = (extensionsRoot) => {
|
||||
/**
|
||||
* @param content {string} The contents of the file
|
||||
* @param path {string} The absolute file path, always using `/`, even on Windows
|
||||
*/
|
||||
const result = (content, path) => {
|
||||
// (2) Patch builtin extensions
|
||||
if (path.endsWith('vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.js')) {
|
||||
const builtinExtensions = JSON.stringify(extensions.scanBuiltinExtensions(extensionsRoot));
|
||||
return content.replace('/*BUILD->INSERT_BUILTIN_EXTENSIONS*/', () => builtinExtensions.substr(1, builtinExtensions.length - 2) /* without [ and ]*/);
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param patchers {((content:string, path: string)=>string)[]}
|
||||
*/
|
||||
const combineContentPatchers = (...patchers) => {
|
||||
/**
|
||||
* @param content {string} The contents of the file
|
||||
* @param path {string} The absolute file path, always using `/`, even on Windows
|
||||
*/
|
||||
const result = (content, path) => {
|
||||
for (const patcher of patchers) {
|
||||
content = patcher(content, path);
|
||||
}
|
||||
return content;
|
||||
};
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param extensionsRoot {string} The location where extension will be read from
|
||||
* @param {object} product The parsed product.json file contents
|
||||
*/
|
||||
const createVSCodeWebFileContentMapper = (extensionsRoot, product) => {
|
||||
return combineContentPatchers(
|
||||
createVSCodeWebProductConfigurationPatcher(product),
|
||||
createVSCodeWebBuiltinExtensionsPatcher(extensionsRoot)
|
||||
);
|
||||
return path => {
|
||||
if (path.endsWith('vs/platform/product/common/product.js')) {
|
||||
return content => {
|
||||
const productConfiguration = JSON.stringify({
|
||||
...product,
|
||||
version,
|
||||
commit,
|
||||
date: readISODate('out-build')
|
||||
});
|
||||
return content.replace('/*BUILD->INSERT_PRODUCT_CONFIGURATION*/', () => productConfiguration.substr(1, productConfiguration.length - 2) /* without { and }*/);
|
||||
};
|
||||
} else if (path.endsWith('vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.js')) {
|
||||
return content => {
|
||||
const builtinExtensions = JSON.stringify(extensions.scanBuiltinExtensions(extensionsRoot));
|
||||
return content.replace('/*BUILD->INSERT_BUILTIN_EXTENSIONS*/', () => builtinExtensions.substr(1, builtinExtensions.length - 2) /* without [ and ]*/);
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
};
|
||||
exports.createVSCodeWebFileContentMapper = createVSCodeWebFileContentMapper;
|
||||
|
||||
|
|
|
@ -53,18 +53,24 @@ function optimizeESMTask(opts) {
|
|||
};
|
||||
const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js');
|
||||
banner.js += await fs.promises.readFile(tslibPath, 'utf-8');
|
||||
const boilerplateTrimmer = {
|
||||
name: 'boilerplate-trimmer',
|
||||
const contentsMapper = {
|
||||
name: 'contents-mapper',
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.js$/ }, async (args) => {
|
||||
const contents = await fs.promises.readFile(args.path, 'utf-8');
|
||||
const newContents = bundle.removeAllTSBoilerplate(contents);
|
||||
build.onLoad({ filter: /\.js$/ }, async ({ path }) => {
|
||||
// TS Boilerplate
|
||||
const contents = await fs.promises.readFile(path, 'utf-8');
|
||||
let newContents = bundle.removeAllTSBoilerplate(contents);
|
||||
// File Content Mapper
|
||||
const mapper = opts.fileContentMapper?.(path);
|
||||
if (mapper) {
|
||||
newContents = mapper(newContents);
|
||||
}
|
||||
return { contents: newContents };
|
||||
});
|
||||
}
|
||||
};
|
||||
const overrideExternalPlugin = {
|
||||
name: 'override-external',
|
||||
const externalOverride = {
|
||||
name: 'external-override',
|
||||
setup(build) {
|
||||
// We inline selected modules that are we depend on on startup without
|
||||
// a conditional `await import(...)` by hooking into the resolution.
|
||||
|
@ -80,7 +86,7 @@ function optimizeESMTask(opts) {
|
|||
platform: 'neutral', // makes esm
|
||||
format: 'esm',
|
||||
sourcemap: 'external',
|
||||
plugins: [boilerplateTrimmer, overrideExternalPlugin],
|
||||
plugins: [contentsMapper, externalOverride],
|
||||
target: ['es2022'],
|
||||
loader: {
|
||||
'.ttf': 'file',
|
||||
|
@ -101,23 +107,12 @@ function optimizeESMTask(opts) {
|
|||
metafile: true, // enables res.metafile
|
||||
}).then(res => {
|
||||
for (const file of res.outputFiles) {
|
||||
let contents = file.contents;
|
||||
let sourceMapFile = undefined;
|
||||
if (file.path.endsWith('.js')) {
|
||||
if (opts.fileContentMapper) {
|
||||
// UGLY the fileContentMapper is per file but at this point we have all files
|
||||
// bundled already. So, we call the mapper for the same contents but each file
|
||||
// that has been included in the bundle...
|
||||
let newText = file.text;
|
||||
for (const input of Object.keys(res.metafile.inputs)) {
|
||||
newText = opts.fileContentMapper(newText, input);
|
||||
}
|
||||
contents = Buffer.from(newText);
|
||||
}
|
||||
sourceMapFile = res.outputFiles.find(f => f.path === `${file.path}.map`);
|
||||
}
|
||||
const fileProps = {
|
||||
contents: Buffer.from(contents),
|
||||
contents: Buffer.from(file.contents),
|
||||
sourceMap: sourceMapFile ? JSON.parse(sourceMapFile.text) : undefined, // support gulp-sourcemaps
|
||||
path: file.path,
|
||||
base: path.join(REPO_ROOT_PATH, opts.src)
|
||||
|
|
|
@ -32,11 +32,9 @@ export interface IOptimizeESMTaskOpts {
|
|||
*/
|
||||
resources?: string[];
|
||||
/**
|
||||
* File contents interceptor
|
||||
* @param contents The contents of the file
|
||||
* @param path The absolute file path, always using `/`, even on Windows
|
||||
* File contents interceptor for a given path.
|
||||
*/
|
||||
fileContentMapper?: (contents: string, path: string) => string;
|
||||
fileContentMapper?: (path: string) => ((contents: string) => string) | undefined;
|
||||
}
|
||||
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
|
@ -83,19 +81,28 @@ function optimizeESMTask(opts: IOptimizeESMTaskOpts): NodeJS.ReadWriteStream {
|
|||
const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js');
|
||||
banner.js += await fs.promises.readFile(tslibPath, 'utf-8');
|
||||
|
||||
const boilerplateTrimmer: esbuild.Plugin = {
|
||||
name: 'boilerplate-trimmer',
|
||||
const contentsMapper: esbuild.Plugin = {
|
||||
name: 'contents-mapper',
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.js$/ }, async args => {
|
||||
const contents = await fs.promises.readFile(args.path, 'utf-8');
|
||||
const newContents = bundle.removeAllTSBoilerplate(contents);
|
||||
build.onLoad({ filter: /\.js$/ }, async ({ path }) => {
|
||||
|
||||
// TS Boilerplate
|
||||
const contents = await fs.promises.readFile(path, 'utf-8');
|
||||
let newContents = bundle.removeAllTSBoilerplate(contents);
|
||||
|
||||
// File Content Mapper
|
||||
const mapper = opts.fileContentMapper?.(path);
|
||||
if (mapper) {
|
||||
newContents = mapper(newContents);
|
||||
}
|
||||
|
||||
return { contents: newContents };
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const overrideExternalPlugin: esbuild.Plugin = {
|
||||
name: 'override-external',
|
||||
const externalOverride: esbuild.Plugin = {
|
||||
name: 'external-override',
|
||||
setup(build) {
|
||||
// We inline selected modules that are we depend on on startup without
|
||||
// a conditional `await import(...)` by hooking into the resolution.
|
||||
|
@ -112,7 +119,7 @@ function optimizeESMTask(opts: IOptimizeESMTaskOpts): NodeJS.ReadWriteStream {
|
|||
platform: 'neutral', // makes esm
|
||||
format: 'esm',
|
||||
sourcemap: 'external',
|
||||
plugins: [boilerplateTrimmer, overrideExternalPlugin],
|
||||
plugins: [contentsMapper, externalOverride],
|
||||
target: ['es2022'],
|
||||
loader: {
|
||||
'.ttf': 'file',
|
||||
|
@ -135,27 +142,14 @@ function optimizeESMTask(opts: IOptimizeESMTaskOpts): NodeJS.ReadWriteStream {
|
|||
}).then(res => {
|
||||
for (const file of res.outputFiles) {
|
||||
|
||||
let contents = file.contents;
|
||||
let sourceMapFile: esbuild.OutputFile | undefined = undefined;
|
||||
|
||||
if (file.path.endsWith('.js')) {
|
||||
|
||||
if (opts.fileContentMapper) {
|
||||
// UGLY the fileContentMapper is per file but at this point we have all files
|
||||
// bundled already. So, we call the mapper for the same contents but each file
|
||||
// that has been included in the bundle...
|
||||
let newText = file.text;
|
||||
for (const input of Object.keys(res.metafile.inputs)) {
|
||||
newText = opts.fileContentMapper(newText, input);
|
||||
}
|
||||
contents = Buffer.from(newText);
|
||||
}
|
||||
|
||||
sourceMapFile = res.outputFiles.find(f => f.path === `${file.path}.map`);
|
||||
}
|
||||
|
||||
const fileProps = {
|
||||
contents: Buffer.from(contents),
|
||||
contents: Buffer.from(file.contents),
|
||||
sourceMap: sourceMapFile ? JSON.parse(sourceMapFile.text) : undefined, // support gulp-sourcemaps
|
||||
path: file.path,
|
||||
base: path.join(REPO_ROOT_PATH, opts.src)
|
||||
|
|
Loading…
Reference in New Issue