esm - some build polish (#225948)

This commit is contained in:
Benjamin Pasero 2024-08-19 16:54:29 +02:00 committed by GitHub
parent ec34e3440e
commit 3dc8c38c92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 317 additions and 234 deletions

View File

@ -28,10 +28,11 @@ const fs = require('fs');
const glob = require('glob');
const { compileBuildTask } = require('./gulpfile.compile');
const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions');
const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');
const { vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');
const cp = require('child_process');
const log = require('fancy-log');
const { isESM } = require('./lib/esm');
const buildfile = require('../src/buildfile');
const REPO_ROOT = path.dirname(__dirname);
const commit = getVersion(REPO_ROOT);
@ -87,7 +88,11 @@ const serverResources = [
...serverResourceExcludes
];
const serverWithWebResourceIncludes = [
const serverWithWebResourceIncludes = isESM() ? [
...serverResourceIncludes,
'out-build/vs/code/browser/workbench/*.html',
...vscodeWebResourceIncludes
] : [
...serverResourceIncludes,
...vscodeWebResourceIncludes
];
@ -126,14 +131,35 @@ const serverEntryPoints = [
}
];
const webEntryPoints = isESM() ? [
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerOutputLinks,
buildfile.workerBackgroundTokenization,
buildfile.keyboardMaps,
buildfile.codeWeb
].flat() : [
buildfile.entrypoint('vs/workbench/workbench.web.main'),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.keyboardMaps,
buildfile.workbenchWeb()
].flat();
const serverWithWebEntryPoints = [
// Include all of server
...serverEntryPoints,
// Include workbench web
...vscodeWebEntryPoints
];
// Include all of web
...webEntryPoints,
].flat();
const commonJSEntryPoints = [
'out-build/server-main.js',

View File

@ -38,7 +38,18 @@ const glob = promisify(require('glob'));
const rcedit = promisify(require('rcedit'));
// Build
const vscodeEntryPoints = [
const vscodeEntryPoints = isESM() ? [
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workerOutputLinks,
buildfile.workerBackgroundTokenization,
buildfile.workbenchDesktop(),
buildfile.code
].flat() : [
buildfile.entrypoint('vs/workbench/workbench.desktop.main'),
buildfile.base,
buildfile.workerExtensionHost,
@ -46,11 +57,62 @@ const vscodeEntryPoints = [
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop,
buildfile.workbenchDesktop(),
buildfile.code
].flat();
const vscodeResources = [
const vscodeResourceIncludes = isESM() ? [
// NLS
'out-build/nls.messages.json',
'out-build/nls.keys.json',
// Workbench
'out-build/vs/code/electron-sandbox/workbench/workbench.esm.html',
// Electron Preload
'out-build/vs/base/parts/sandbox/electron-sandbox/preload.js',
'out-build/vs/base/parts/sandbox/electron-sandbox/preload-aux.js',
// Node Scripts
'out-build/vs/base/node/{terminateProcess.sh,cpuUsage.sh,ps.sh}',
// Touchbar
'out-build/vs/workbench/browser/parts/editor/media/*.png',
'out-build/vs/workbench/contrib/debug/browser/media/*.png',
// External Terminal
'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt',
// Terminal shell integration
'out-build/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/*.fish',
'out-build/vs/workbench/contrib/terminal/browser/media/*.ps1',
'out-build/vs/workbench/contrib/terminal/browser/media/*.psm1',
'out-build/vs/workbench/contrib/terminal/browser/media/*.sh',
'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh',
// Accessibility Signals
'out-build/vs/platform/accessibilitySignal/browser/media/*.mp3',
// Welcome
'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}',
// Extensions
'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}',
'out-build/vs/workbench/services/extensionManagement/common/media/*.{svg,png}',
// Webview
'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}',
// Extension Host Worker
'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html',
// Process Explorer
'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html',
// Issue Reporter
'out-build/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html'
] : [
'out-build/nls.messages.json',
'out-build/nls.keys.json',
'out-build/vs/**/*.{svg,png,html,jpg,mp3}',
@ -78,6 +140,21 @@ const vscodeResources = [
'!**/test/**'
];
const vscodeResources = [
// Includes
...vscodeResourceIncludes,
// Excludes
'!out-build/vs/code/browser/**',
'!out-build/vs/editor/standalone/**',
'!out-build/vs/code/**/*-dev.html',
'!out-build/vs/code/**/*-dev.esm.html',
'!out-build/vs/workbench/contrib/issue/**/*-dev.html',
'!out-build/vs/workbench/contrib/issue/**/*-dev.esm.html',
'!**/test/**'
];
// Do not change the order of these files! They will
// be inlined into the target window file in this order
// and they depend on each other in this way.
@ -215,7 +292,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
'vs/workbench/workbench.desktop.main.js',
'vs/workbench/workbench.desktop.main.css',
'vs/workbench/api/node/extensionHostProcess.js',
'vs/code/electron-sandbox/workbench/workbench.html',
isESM() ? 'vs/code/electron-sandbox/workbench/workbench.esm.html' : 'vs/code/electron-sandbox/workbench/workbench.html',
'vs/code/electron-sandbox/workbench/workbench.js'
]);
@ -244,6 +321,11 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
version += '-' + quality;
}
if (isESM() && quality !== 'exploration') {
// TODO@esm remove this safeguard
throw new Error('Refuse to build ESM on quality other than exploration');
}
const name = product.nameShort;
const packageJsonUpdates = { name, version, ...(isESM(`Setting 'type: module' and 'main: out/main.js' in top level package.json`) ? { type: 'module', main: 'out/main.js' } : {}) }; // TODO@esm this should be configured in the top level package.json

View File

@ -21,6 +21,7 @@ const vfs = require('vinyl-fs');
const packageJson = require('../package.json');
const { compileBuildTask } = require('./gulpfile.compile');
const extensions = require('./lib/extensions');
const { isESM } = require('./lib/esm');
const REPO_ROOT = path.dirname(__dirname);
const BUILD_ROOT = path.dirname(REPO_ROOT);
@ -30,7 +31,27 @@ const commit = getVersion(REPO_ROOT);
const quality = product.quality;
const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version;
const vscodeWebResourceIncludes = [
const vscodeWebResourceIncludes = isESM() ? [
// NLS
'out-build/nls.messages.js',
// Accessibility Signals
'out-build/vs/platform/accessibilitySignal/browser/media/*.mp3',
// Welcome
'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}',
// Extensions
'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}',
'out-build/vs/workbench/services/extensionManagement/common/media/*.{svg,png}',
// Webview
'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}',
// Extension Host Worker
'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html',
]: [
// Workbench
'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,jpg,mp3}',
@ -47,7 +68,6 @@ const vscodeWebResourceIncludes = [
// Extension Worker
'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html',
'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html',
// Web node paths (needed for integration tests)
'out-build/vs/webPackagePaths.js',
@ -70,7 +90,17 @@ const vscodeWebResources = [
const buildfile = require('../src/buildfile');
const vscodeWebEntryPoints = [
const vscodeWebEntryPoints = isESM() ? [
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerOutputLinks,
buildfile.workerBackgroundTokenization,
buildfile.keyboardMaps,
buildfile.workbenchWeb()
].flat() : [
buildfile.entrypoint('vs/workbench/workbench.web.main'),
buildfile.base,
buildfile.workerExtensionHost,
@ -78,9 +108,8 @@ const vscodeWebEntryPoints = [
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.keyboardMaps,
buildfile.workbenchWeb
buildfile.workbenchWeb()
].flat();
exports.vscodeWebEntryPoints = vscodeWebEntryPoints;
/**
* @param {object} product The parsed product.json file contents

View File

@ -55,9 +55,6 @@ function bundle(entryPoints, config, callback) {
};
for (const moduleId in entryPointsMap) {
const entryPoint = entryPointsMap[moduleId];
if (entryPoint.append) {
entryPoint.append = entryPoint.append.map(resolvePath);
}
if (entryPoint.prepend) {
entryPoint.prepend = entryPoint.prepend.map(resolvePath);
}
@ -105,7 +102,7 @@ function emitEntryPoints(modules, entryPoints) {
return allDependencies[module];
});
bundleData.bundles[moduleToBundle] = includedModules;
const res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules, info.prepend || [], info.append || [], info.dest);
const res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules, info.prepend || [], info.dest);
result = result.concat(res.files);
for (const pluginName in res.usedPlugins) {
usedPlugins[pluginName] = usedPlugins[pluginName] || res.usedPlugins[pluginName];
@ -278,7 +275,7 @@ function removeDuplicateTSBoilerplate(source, SEEN_BOILERPLATE = []) {
}
return newLines.join('\n');
}
function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, append, dest) {
function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, dest) {
if (!dest) {
dest = entryPoint + '.js';
}
@ -352,8 +349,7 @@ function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend,
};
};
const toPrepend = (prepend || []).map(toIFile);
const toAppend = (append || []).map(toIFile);
mainResult.sources = toPrepend.concat(mainResult.sources).concat(toAppend);
mainResult.sources = toPrepend.concat(mainResult.sources);
return {
files: results,
usedPlugins: usedPlugins

View File

@ -52,7 +52,6 @@ export interface IEntryPoint {
include?: string[];
exclude?: string[];
prepend?: IExtraFile[];
append?: IExtraFile[];
dest?: string;
target?: 'amd' | 'esm';
}
@ -158,9 +157,6 @@ export function bundle(entryPoints: IEntryPoint[], config: ILoaderConfig, callba
};
for (const moduleId in entryPointsMap) {
const entryPoint = entryPointsMap[moduleId];
if (entryPoint.append) {
entryPoint.append = entryPoint.append.map(resolvePath);
}
if (entryPoint.prepend) {
entryPoint.prepend = entryPoint.prepend.map(resolvePath);
}
@ -224,7 +220,6 @@ function emitEntryPoints(modules: IBuildModuleInfo[], entryPoints: IEntryPointMa
moduleToBundle,
includedModules,
info.prepend || [],
info.append || [],
info.dest
);
@ -430,7 +425,6 @@ function emitEntryPoint(
entryPoint: string,
includedModules: string[],
prepend: IExtraFile[],
append: IExtraFile[],
dest: string | undefined
): IEmitEntryPointResult {
if (!dest) {
@ -516,9 +510,8 @@ function emitEntryPoint(
};
const toPrepend = (prepend || []).map(toIFile);
const toAppend = (append || []).map(toIFile);
mainResult.sources = toPrepend.concat(mainResult.sources).concat(toAppend);
mainResult.sources = toPrepend.concat(mainResult.sources);
return {
files: results,

View File

@ -28,9 +28,9 @@ function setESM(enabled) {
}
function isESM(logWarning) {
try {
const res = fs.readFileSync(esmMarkerFile, 'utf8') === 'true';
const res = (typeof process.env.VSCODE_BUILD_ESM === 'string' && process.env.VSCODE_BUILD_ESM.toLowerCase() === 'true') || (fs.readFileSync(esmMarkerFile, 'utf8') === 'true');
if (res && logWarning) {
console.warn(`ESM: ${logWarning}`);
console.warn(`[esm] ${logWarning}`);
}
return res;
}

View File

@ -29,9 +29,9 @@ export function setESM(enabled: boolean) {
export function isESM(logWarning?: string): boolean {
try {
const res = fs.readFileSync(esmMarkerFile, 'utf8') === 'true';
const res = (typeof process.env.VSCODE_BUILD_ESM === 'string' && process.env.VSCODE_BUILD_ESM.toLowerCase() === 'true') || (fs.readFileSync(esmMarkerFile, 'utf8') === 'true');
if (res && logWarning) {
console.warn(`ESM: ${logWarning}`);
console.warn(`[esm] ${logWarning}`);
}
return res;
} catch (error) {

View File

@ -316,7 +316,7 @@ globalThis._VSCODE_NLS_LANGUAGE=${JSON.stringify(language.id)};`),
function processNlsFiles(opts) {
return (0, event_stream_1.through)(function (file) {
const fileName = path.basename(file.path);
if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles
if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles (TODO@esm this file is not created anymore, pick another)
try {
const json = JSON.parse(fs.readFileSync(path.join(REPO_ROOT_PATH, opts.out, 'nls.keys.json')).toString());
if (NLSKeysFormat.is(json)) {

View File

@ -387,7 +387,7 @@ globalThis._VSCODE_NLS_LANGUAGE=${JSON.stringify(language.id)};`),
export function processNlsFiles(opts: { out: string; fileHeader: string; languages: Language[] }): ThroughStream {
return through(function (this: ThroughStream, file: File) {
const fileName = path.basename(file.path);
if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles
if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles (TODO@esm this file is not created anymore, pick another)
try {
const json = JSON.parse(fs.readFileSync(path.join(REPO_ROOT_PATH, opts.out, 'nls.keys.json')).toString());
if (NLSKeysFormat.is(json)) {

View File

@ -14,6 +14,7 @@ const ts = require("typescript");
const url_1 = require("url");
const workerpool = require("workerpool");
const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost");
const esm_1 = require("../esm");
const buildfile = require('../../../src/buildfile');
class ShortIdent {
prefix;
@ -247,35 +248,51 @@ function isNameTakenInFile(node, name) {
}
return false;
}
const skippedExportMangledFiles = [
// Build
'css.build',
// Monaco
'editorCommon',
'editorOptions',
'editorZoom',
'standaloneEditor',
'standaloneEnums',
'standaloneLanguages',
// Generated
'extensionsApiProposals',
// Module passed around as type
'pfs',
// entry points
...[
buildfile.entrypoint('vs/server/node/server.main', []),
buildfile.entrypoint('vs/workbench/workbench.desktop.main', []),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop,
buildfile.workbenchWeb,
buildfile.code
].flat().map(x => x.name),
];
const skippedExportMangledFiles = function () {
return [
// Build
'css.build',
// Monaco
'editorCommon',
'editorOptions',
'editorZoom',
'standaloneEditor',
'standaloneEnums',
'standaloneLanguages',
// Generated
'extensionsApiProposals',
// Module passed around as type
'pfs',
// entry points
...(0, esm_1.isESM)() ? [
buildfile.entrypoint('vs/server/node/server.main'),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workerOutputLinks,
buildfile.workerBackgroundTokenization,
buildfile.workbenchDesktop(),
buildfile.workbenchWeb(),
buildfile.code,
buildfile.codeWeb
].flat().map(x => x.name) : [
buildfile.entrypoint('vs/server/node/server.main'),
buildfile.entrypoint('vs/workbench/workbench.desktop.main'),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop(),
buildfile.workbenchWeb(),
buildfile.code
].flat().map(x => x.name),
];
};
const skippedExportMangledProjects = [
// Test projects
'vscode-api-tests',
@ -519,7 +536,7 @@ class Mangler {
for (const data of this.allExportedSymbols.values()) {
if (data.fileName.endsWith('.d.ts')
|| skippedExportMangledProjects.some(proj => data.fileName.includes(proj))
|| skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))) {
|| skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts'))) {
continue;
}
if (!data.shouldMangle(data.replacementName)) {

View File

@ -12,6 +12,7 @@ import * as ts from 'typescript';
import { pathToFileURL } from 'url';
import * as workerpool from 'workerpool';
import { StaticLanguageServiceHost } from './staticLanguageServiceHost';
import { isESM } from '../esm';
const buildfile = require('../../../src/buildfile');
class ShortIdent {
@ -279,40 +280,55 @@ function isNameTakenInFile(node: ts.Node, name: string): boolean {
return false;
}
const skippedExportMangledFiles = function () { // using a function() to ensure late isESM() check
return [
// Build
'css.build',
const skippedExportMangledFiles = [
// Build
'css.build',
// Monaco
'editorCommon',
'editorOptions',
'editorZoom',
'standaloneEditor',
'standaloneEnums',
'standaloneLanguages',
// Monaco
'editorCommon',
'editorOptions',
'editorZoom',
'standaloneEditor',
'standaloneEnums',
'standaloneLanguages',
// Generated
'extensionsApiProposals',
// Generated
'extensionsApiProposals',
// Module passed around as type
'pfs',
// Module passed around as type
'pfs',
// entry points
...[
buildfile.entrypoint('vs/server/node/server.main', []),
buildfile.entrypoint('vs/workbench/workbench.desktop.main', []),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop,
buildfile.workbenchWeb,
buildfile.code
].flat().map(x => x.name),
];
// entry points
...isESM() ? [
buildfile.entrypoint('vs/server/node/server.main'),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workerOutputLinks,
buildfile.workerBackgroundTokenization,
buildfile.workbenchDesktop(),
buildfile.workbenchWeb(),
buildfile.code,
buildfile.codeWeb
].flat().map(x => x.name) : [
buildfile.entrypoint('vs/server/node/server.main'),
buildfile.entrypoint('vs/workbench/workbench.desktop.main'),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop(),
buildfile.workbenchWeb(),
buildfile.code
].flat().map(x => x.name),
];
};
const skippedExportMangledProjects = [
// Test projects
@ -609,7 +625,7 @@ export class Mangler {
for (const data of this.allExportedSymbols.values()) {
if (data.fileName.endsWith('.d.ts')
|| skippedExportMangledProjects.some(proj => data.fileName.includes(proj))
|| skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))
|| skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts'))
) {
continue;
}

View File

@ -15,6 +15,7 @@ const filter = require("gulp-filter");
const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors");
const path = require("path");
const fs = require("fs");
const pump = require("pump");
const VinylFile = require("vinyl");
const bundle = require("./bundle");
@ -22,6 +23,8 @@ const i18n_1 = require("./i18n");
const stats_1 = require("./stats");
const util = require("./util");
const postcss_1 = require("./postcss");
const esbuild = require("esbuild");
const sourcemaps = require("gulp-sourcemaps");
const esm_1 = require("./esm");
const REPO_ROOT_PATH = path.join(__dirname, '../..');
function log(prefix, message) {
@ -154,7 +157,6 @@ function optimizeAMDTask(opts) {
const loaderConfig = opts.loaderConfig;
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents);
const sourcemaps = require('gulp-sourcemaps');
const bundlesStream = es.through(); // this stream will contain the bundled files
const resourcesStream = es.through(); // this stream will contain the resources
const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
@ -196,40 +198,29 @@ function optimizeAMDTask(opts) {
}) : es.through());
}
function optimizeESMTask(opts, cjsOpts) {
// TODO@esm honor IEntryPoint#prepred/append (unused?)
const esbuild = require('esbuild');
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const sourcemaps = require('gulp-sourcemaps');
const resourcesStream = es.through(); // this stream will contain the resources
const bundlesStream = es.through(); // this stream will contain the bundled files
const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd');
if (cjsOpts) {
cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name }));
}
// TODO@esm remove hardcoded entry point and support `dest` of `IEntryPoint` or clean that up
entryPoints.push({ name: 'vs/base/worker/workerMain' });
entryPoints.push({ name: 'vs/base/worker/workerMain' }); // TODO@esm remove hardcoded entry point when workers are cleaned up
const allMentionedModules = new Set();
for (const entryPoint of entryPoints) {
allMentionedModules.add(entryPoint.name);
entryPoint.include?.forEach(allMentionedModules.add, allMentionedModules);
entryPoint.exclude?.forEach(allMentionedModules.add, allMentionedModules);
}
// TODO@esm remove this from the bundle files
allMentionedModules.delete('vs/css');
allMentionedModules.delete('vs/css'); // TODO@esm remove this when vs/css is removed
const bundleAsync = async () => {
let bundleData;
const files = [];
const tasks = [];
for (const entryPoint of entryPoints) {
const t1 = performance.now();
console.log(`[bundle] STARTING '${entryPoint.name}'...`);
console.log(`[bundle] '${entryPoint.name}'`);
// support for 'dest' via esbuild#in/out
const dest = entryPoint.dest?.replace(/\.[^/.]+$/, '') ?? entryPoint.name;
// const dest = entryPoint.name;
// boilerplate massage
const banner = { js: '' };
const fs = await Promise.resolve().then(() => require('node:fs'));
const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js');
banner.js += await fs.promises.readFile(tslibPath, 'utf-8');
const boilerplateTrimmer = {
@ -251,20 +242,20 @@ function optimizeESMTask(opts, cjsOpts) {
}
}
const task = esbuild.build({
logLevel: 'silent',
bundle: true,
external: entryPoint.exclude,
packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages
platform: 'neutral', // makes esm
format: 'esm',
plugins: [boilerplateTrimmer],
target: ['es2023'],
target: ['es2022'],
loader: {
'.ttf': 'file',
'.svg': 'file',
'.png': 'file',
'.sh': 'file',
},
assetNames: 'media/[name]', // moves media assets into a sub-folder "media"
banner,
entryPoints: [
{
@ -276,25 +267,6 @@ function optimizeESMTask(opts, cjsOpts) {
write: false, // enables res.outputFiles
metafile: true, // enables res.metafile
}).then(res => {
console.log(`[bundle] DONE for '${entryPoint.name}' (${Math.round(performance.now() - t1)}ms)`);
if (opts.bundleInfo) {
// TODO@esm validate that bundleData is correct
bundleData ??= { graph: {}, bundles: {} };
function pathToModule(path) {
return path
.replace(new RegExp(`^${opts.src}\\/`), '')
.replace(/\.js$/, '');
}
for (const [path, value] of Object.entries(res.metafile.outputs)) {
const entryModule = pathToModule(path);
const inputModules = Object.keys(value.inputs).map(pathToModule);
bundleData.bundles[entryModule] = inputModules;
}
for (const [input, value] of Object.entries(res.metafile.inputs)) {
const dependencies = value.imports.map(i => pathToModule(i.path));
bundleData.graph[pathToModule(input)] = dependencies;
}
}
for (const file of res.outputFiles) {
let contents = file.contents;
if (file.path.endsWith('.js')) {
@ -320,25 +292,15 @@ function optimizeESMTask(opts, cjsOpts) {
tasks.push(task);
}
await Promise.all(tasks);
return { files, bundleData };
return { files };
};
bundleAsync().then((output) => {
// bundle output (JS, CSS, SVG...)
es.readArray(output.files).pipe(bundlesStream);
// bundeInfo.json
const bundleInfoArray = [];
if (typeof output.bundleData === 'object') {
bundleInfoArray.push(new VinylFile({
path: 'bundleInfo.json',
base: '.',
contents: Buffer.from(JSON.stringify(output.bundleData, null, '\t'))
}));
}
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
// forward all resources
gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
});
const result = es.merge(bundlesStream, resourcesStream, bundleInfoStream);
const result = es.merge(bundlesStream, resourcesStream);
return result
.pipe(sourcemaps.write('./', {
sourceRoot: undefined,
@ -347,12 +309,11 @@ function optimizeESMTask(opts, cjsOpts) {
}))
.pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({
out: opts.src,
fileHeader: bundledFileHeader,
fileHeader: opts.header || DEFAULT_FILE_HEADER,
languages: opts.languages
}) : es.through());
}
function optimizeCommonJSTask(opts) {
const esbuild = require('esbuild');
const src = opts.src;
const entryPoints = opts.entryPoints;
return gulp.src(entryPoints, { base: `${src}`, allowEmpty: true })
@ -400,11 +361,9 @@ function optimizeTask(opts) {
};
}
function minifyTask(src, sourceMapBaseUrl) {
const esbuild = require('esbuild');
const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
return cb => {
const cssnano = require('cssnano');
const sourcemaps = require('gulp-sourcemaps');
const svgmin = require('gulp-svgmin');
const jsFilter = filter('**/*.js', { restore: true });
const cssFilter = filter('**/*.css', { restore: true });
@ -416,7 +375,7 @@ function minifyTask(src, sourceMapBaseUrl) {
sourcemap: 'external',
outdir: '.',
platform: 'node',
target: ['esnext'],
target: ['es2022'],
write: false
}).then(res => {
const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path));

View File

@ -10,6 +10,7 @@ import * as filter from 'gulp-filter';
import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors';
import * as path from 'path';
import * as fs from 'fs';
import * as pump from 'pump';
import * as VinylFile from 'vinyl';
import * as bundle from './bundle';
@ -17,7 +18,8 @@ import { Language, processNlsFiles } from './i18n';
import { createStatsStream } from './stats';
import * as util from './util';
import { gulpPostcss } from './postcss';
import type { Plugin } from 'esbuild';
import * as esbuild from 'esbuild';
import * as sourcemaps from 'gulp-sourcemaps';
import { isESM } from './esm';
const REPO_ROOT_PATH = path.join(__dirname, '../..');
@ -221,8 +223,6 @@ function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream {
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents);
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
const bundlesStream = es.through(); // this stream will contain the bundled files
const resourcesStream = es.through(); // this stream will contain the resources
const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
@ -274,24 +274,15 @@ function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream {
}
function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream {
// TODO@esm honor IEntryPoint#prepred/append (unused?)
const esbuild = require('esbuild') as typeof import('esbuild');
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
const resourcesStream = es.through(); // this stream will contain the resources
const bundlesStream = es.through(); // this stream will contain the bundled files
const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd');
if (cjsOpts) {
cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name }));
}
// TODO@esm remove hardcoded entry point and support `dest` of `IEntryPoint` or clean that up
entryPoints.push({ name: 'vs/base/worker/workerMain' });
entryPoints.push({ name: 'vs/base/worker/workerMain' }); // TODO@esm remove hardcoded entry point when workers are cleaned up
const allMentionedModules = new Set<string>();
for (const entryPoint of entryPoints) {
@ -300,31 +291,26 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
entryPoint.exclude?.forEach(allMentionedModules.add, allMentionedModules);
}
// TODO@esm remove this from the bundle files
allMentionedModules.delete('vs/css');
allMentionedModules.delete('vs/css'); // TODO@esm remove this when vs/css is removed
const bundleAsync = async () => {
let bundleData: bundle.IBundleData | undefined;
const files: VinylFile[] = [];
const tasks: Promise<any>[] = [];
for (const entryPoint of entryPoints) {
const t1 = performance.now();
console.log(`[bundle] STARTING '${entryPoint.name}'...`);
console.log(`[bundle] '${entryPoint.name}'`);
// support for 'dest' via esbuild#in/out
const dest = entryPoint.dest?.replace(/\.[^/.]+$/, '') ?? entryPoint.name;
// const dest = entryPoint.name;
// boilerplate massage
const banner = { js: '' };
const fs = await import('node:fs');
const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js');
banner.js += await fs.promises.readFile(tslibPath, 'utf-8');
const boilerplateTrimmer: Plugin = {
const boilerplateTrimmer: esbuild.Plugin = {
name: 'boilerplate-trimmer',
setup(build) {
build.onLoad({ filter: /\.js$/ }, async args => {
@ -344,22 +330,21 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
}
}
const task = esbuild.build({
logLevel: 'silent',
bundle: true,
external: entryPoint.exclude,
packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages
platform: 'neutral', // makes esm
format: 'esm',
plugins: [boilerplateTrimmer],
target: ['es2023'],
target: ['es2022'],
loader: {
'.ttf': 'file',
'.svg': 'file',
'.png': 'file',
'.sh': 'file',
},
assetNames: 'media/[name]', // moves media assets into a sub-folder "media"
banner,
entryPoints: [
{
@ -372,30 +357,6 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
metafile: true, // enables res.metafile
}).then(res => {
console.log(`[bundle] DONE for '${entryPoint.name}' (${Math.round(performance.now() - t1)}ms)`);
if (opts.bundleInfo) {
// TODO@esm validate that bundleData is correct
bundleData ??= { graph: {}, bundles: {} };
function pathToModule(path: string) {
return path
.replace(new RegExp(`^${opts.src}\\/`), '')
.replace(/\.js$/, '');
}
for (const [path, value] of Object.entries(res.metafile.outputs)) {
const entryModule = pathToModule(path);
const inputModules = Object.keys(value.inputs).map(pathToModule);
bundleData.bundles[entryModule] = inputModules;
}
for (const [input, value] of Object.entries(res.metafile.inputs)) {
const dependencies = value.imports.map(i => pathToModule(i.path));
bundleData.graph[pathToModule(input)] = dependencies;
}
}
for (const file of res.outputFiles) {
let contents = file.contents;
@ -427,7 +388,7 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
}
await Promise.all(tasks);
return { files, bundleData };
return { files };
};
bundleAsync().then((output) => {
@ -435,25 +396,13 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
// bundle output (JS, CSS, SVG...)
es.readArray(output.files).pipe(bundlesStream);
// bundeInfo.json
const bundleInfoArray: VinylFile[] = [];
if (typeof output.bundleData === 'object') {
bundleInfoArray.push(new VinylFile({
path: 'bundleInfo.json',
base: '.',
contents: Buffer.from(JSON.stringify(output.bundleData, null, '\t'))
}));
}
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
// forward all resources
gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
});
const result = es.merge(
bundlesStream,
resourcesStream,
bundleInfoStream
resourcesStream
);
return result
@ -464,7 +413,7 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
}))
.pipe(opts.languages && opts.languages.length ? processNlsFiles({
out: opts.src,
fileHeader: bundledFileHeader,
fileHeader: opts.header || DEFAULT_FILE_HEADER,
languages: opts.languages
}) : es.through());
}
@ -489,8 +438,6 @@ export interface IOptimizeCommonJSTaskOpts {
}
function optimizeCommonJSTask(opts: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream {
const esbuild = require('esbuild') as typeof import('esbuild');
const src = opts.src;
const entryPoints = opts.entryPoints;
@ -578,12 +525,10 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
}
export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => void {
const esbuild = require('esbuild') as typeof import('esbuild');
const sourceMappingURL = sourceMapBaseUrl ? ((f: any) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
return cb => {
const cssnano = require('cssnano') as typeof import('cssnano');
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
const svgmin = require('gulp-svgmin') as typeof import('gulp-svgmin');
const jsFilter = filter('**/*.js', { restore: true });
@ -601,7 +546,7 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) =>
sourcemap: 'external',
outdir: '.',
platform: 'node',
target: ['esnext'],
target: ['es2022'],
write: false
}).then(res => {
const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!;

View File

@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const { isESM } = require('../build/lib/esm');
/**
* @param {string} name
* @param {string[]=} exclude
@ -66,22 +68,37 @@ exports.workerNotebook = createEditorWorkerModuleDescription('vs/workbench/contr
exports.workerLanguageDetection = createEditorWorkerModuleDescription('vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker');
exports.workerLocalFileSearch = createEditorWorkerModuleDescription('vs/workbench/services/search/worker/localFileSearch');
exports.workerProfileAnalysis = createEditorWorkerModuleDescription('vs/platform/profiling/electron-sandbox/profileAnalysisWorker');
exports.workerOutputLinks = createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', true);
exports.workerBackgroundTokenization = createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker', true);
exports.workbenchDesktop = [
...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', true),
...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker', true),
createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'),
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'),
];
exports.workbenchDesktop = function () {
return isESM() ? [
createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'),
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'),
createModuleDescription('vs/workbench/workbench.desktop.main')
] : [
...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', true),
...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker', true),
createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'),
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'),
];
};
exports.workbenchWeb = [
...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', true),
...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker', true),
createModuleDescription('vs/code/browser/workbench/workbench', ['vs/workbench/workbench.web.main'])
];
exports.workbenchWeb = function () {
return isESM() ? [
createModuleDescription('vs/workbench/workbench.web.main')
] : [
...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', true),
...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker', true),
createModuleDescription('vs/code/browser/workbench/workbench', ['vs/workbench/workbench.web.main'])
];
};
exports.keyboardMaps = [
createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'),
@ -97,4 +114,8 @@ exports.code = [
createModuleDescription('vs/code/electron-sandbox/processExplorer/processExplorerMain')
];
exports.codeWeb = [
createModuleDescription('vs/code/browser/workbench/workbench')
];
exports.entrypoint = createModuleDescription;

View File

@ -25,7 +25,7 @@
<!-- Workbench Icon/Manifest/CSS -->
<link rel="icon" href="{{WORKBENCH_WEB_BASE_URL}}/resources/server/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="{{WORKBENCH_WEB_BASE_URL}}/resources/server/manifest.json" crossorigin="use-credentials" />
<link data-name="vs/workbench/workbench.web.main" rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/workbench/workbench.web.main.css">
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
</head>

View File

@ -117,8 +117,7 @@ export async function main(argv: string[]): Promise<any> {
// Extensions Management
else if (shouldSpawnCliProcess(args)) {
const cli = await import('vs/code/node/cliProcessMain');
const cli = await import(['vs', 'code', 'node', 'cliProcessMain'].join('/') /* TODO@esm workaround to prevent esbuild from inlining this */);
await cli.main(args);
return;