esm - make `optimize.ts` ESM only

This commit is contained in:
Benjamin Pasero 2024-09-27 08:05:06 +02:00
parent fbd082776d
commit c7caef00ea
No known key found for this signature in database
GPG Key ID: E6380CC4C8219E65
8 changed files with 48 additions and 311 deletions

View File

@ -92,13 +92,10 @@ const compileEditorAMDTask = task.define('compile-editor-amd', compilation.compi
const optimizeEditorAMDTask = task.define('optimize-editor-amd', optimize.optimizeTask(
{
out: 'out-editor',
amd: {
esm: {
src: 'out-editor-build',
entryPoints: editorEntryPoints,
resources: editorResources,
header: BUNDLED_FILE_HEADER,
bundleInfo: true,
languages
resources: editorResources
}
}
));

View File

@ -148,10 +148,10 @@ const serverWithWebEntryPoints = [
...webEntryPoints,
].flat();
const commonJSEntryPoints = [
const bootstrapEntryPoints = [
'out-build/server-main.js',
'out-build/server-cli.js',
'out-build/bootstrap-fork.js',
'out-build/bootstrap-fork.js'
];
function getNodeVersion() {
@ -436,7 +436,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
}
result = inlineMeta(result, {
targetPaths: commonJSEntryPoints,
targetPaths: bootstrapEntryPoints,
packageJsonFn: () => packageJsonContents,
productJsonFn: () => productJsonContents
});
@ -460,28 +460,14 @@ function tweakProductForServerWeb(product) {
optimize.optimizeTask(
{
out: `out-vscode-${type}`,
amd: {
esm: {
src: 'out-build',
entryPoints: (type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints).flat(),
otherSources: [],
entryPoints: [
...(type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints),
...bootstrapEntryPoints
],
resources: type === 'reh' ? serverResources : serverWithWebResources,
inlineAmdImages: true,
bundleInfo: undefined,
fileContentMapper: createVSCodeWebFileContentMapper('.build/extensions', type === 'reh-web' ? tweakProductForServerWeb(product) : product)
},
commonJS: {
src: 'out-build',
entryPoints: commonJSEntryPoints,
platform: 'node',
external: [
'minimist',
// We cannot inline `product.json` from here because
// it is being changed during build time at a later
// point in time (such as `checksums`)
// We have a manual step to inline these later.
'../product.json',
'../package.json'
]
}
}
)

View File

@ -126,7 +126,7 @@ const windowBootstrapFiles = [
'out-build/bootstrap-window.js'
];
const commonJSEntryPoints = [
const bootstrapEntryPoints = [
'out-build/main.js',
'out-build/cli.js',
'out-build/bootstrap-fork.js'
@ -141,27 +141,13 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
optimize.optimizeTask(
{
out: 'out-vscode',
amd: {
esm: {
src: 'out-build',
entryPoints: vscodeEntryPoints,
resources: vscodeResources,
bundleInfo: undefined
},
commonJS: {
src: 'out-build',
entryPoints: commonJSEntryPoints,
platform: 'node',
external: [
'electron',
'minimist',
'original-fs',
// We cannot inline `product.json` from here because
// it is being changed during build time at a later
// point in time (such as `checksums`)
// We have a manual step to inline these later.
'../product.json',
'../package.json',
]
entryPoints: [
...vscodeEntryPoints,
...bootstrapEntryPoints
],
resources: vscodeResources
},
manual: [
{ src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/workbench/workbench.js'], out: 'vs/code/electron-sandbox/workbench/workbench.js' },
@ -444,7 +430,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
}
result = inlineMeta(result, {
targetPaths: commonJSEntryPoints,
targetPaths: bootstrapEntryPoints,
packageJsonFn: () => packageJsonContents,
productJsonFn: () => productJsonContents
});

View File

@ -164,14 +164,10 @@ const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series(
optimize.optimizeTask(
{
out: 'out-vscode-web',
amd: {
esm: {
src: 'out-build',
entryPoints: vscodeWebEntryPoints.flat(),
otherSources: [],
entryPoints: vscodeWebEntryPoints,
resources: vscodeWebResources,
externalLoaderInfo: util.createExternalLoaderConfig(product.webEndpointUrl, commit, quality),
inlineAmdImages: true,
bundleInfo: undefined,
fileContentMapper: createVSCodeWebFileContentMapper('.build/web/extensions', product)
}
}

View File

@ -15,23 +15,19 @@ const fs = require("fs");
const pump = require("pump");
const VinylFile = require("vinyl");
const bundle = require("./bundle");
const i18n_1 = require("./i18n");
const postcss_1 = require("./postcss");
const esbuild = require("esbuild");
const sourcemaps = require("gulp-sourcemaps");
const REPO_ROOT_PATH = path.join(__dirname, '../..');
const DEFAULT_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
function optimizeESMTask(opts, cjsOpts) {
function optimizeESMTask(opts) {
const resourcesStream = es.through(); // this stream will contain the resources
const bundlesStream = es.through(); // this stream will contain the bundled files
const entryPoints = opts.entryPoints;
if (cjsOpts) {
cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name }));
}
const entryPoints = opts.entryPoints.map(entryPoint => {
if (typeof entryPoint === 'string') {
return { name: path.parse(entryPoint).name };
}
return entryPoint;
});
const allMentionedModules = new Set();
for (const entryPoint of entryPoints) {
allMentionedModules.add(entryPoint.name);
@ -133,7 +129,7 @@ function optimizeESMTask(opts, cjsOpts) {
// bundle output (JS, CSS, SVG...)
es.readArray(output.files).pipe(bundlesStream);
// forward all resources
gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
gulp.src(opts.resources ?? [], { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
});
const result = es.merge(bundlesStream, resourcesStream);
return result
@ -141,12 +137,7 @@ function optimizeESMTask(opts, cjsOpts) {
sourceRoot: undefined,
addComment: true,
includeContent: true
}))
.pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({
out: opts.src,
fileHeader: opts.header || DEFAULT_FILE_HEADER,
languages: opts.languages
}) : es.through());
}));
}
function optimizeManualTask(options) {
const concatenations = options.map(opt => {
@ -159,7 +150,7 @@ function optimizeManualTask(options) {
function optimizeTask(opts) {
return function () {
const optimizers = [];
optimizers.push(optimizeESMTask(opts.amd, opts.commonJS));
optimizers.push(optimizeESMTask(opts.esm));
if (opts.manual) {
optimizers.push(optimizeManualTask(opts.manual));
}

View File

@ -12,47 +12,25 @@ import * as fs from 'fs';
import * as pump from 'pump';
import * as VinylFile from 'vinyl';
import * as bundle from './bundle';
import { Language, processNlsFiles } from './i18n';
import * as util from './util';
import { gulpPostcss } from './postcss';
import * as esbuild from 'esbuild';
import * as sourcemaps from 'gulp-sourcemaps';
const REPO_ROOT_PATH = path.join(__dirname, '../..');
export interface IOptimizeAMDTaskOpts {
export interface IOptimizeESMTaskOpts {
/**
* The folder to read files from.
*/
src: string;
/**
* (for AMD files, will get bundled and get Copyright treatment)
* The entry points to bundle.
*/
entryPoints: bundle.IEntryPoint[];
entryPoints: Array<bundle.IEntryPoint | string>;
/**
* (svg, etc.)
* Other resources to consider (svg, etc.)
*/
resources: string[];
/**
* Additional info we append to the end of the loader
*/
externalLoaderInfo?: util.IExternalLoaderInfo;
/**
* (true by default - append css and nls to loader)
*/
bundleLoader?: boolean;
/**
* (basically the Copyright treatment)
*/
header?: string;
/**
* (emit bundleInfo.json file)
*/
bundleInfo: boolean;
/**
* Language configuration.
*/
languages?: Language[];
resources?: string[];
/**
* File contents interceptor
* @param contents The contents of the file
@ -61,20 +39,16 @@ export interface IOptimizeAMDTaskOpts {
fileContentMapper?: (contents: string, path: string) => string;
}
const DEFAULT_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream {
function optimizeESMTask(opts: IOptimizeESMTaskOpts): NodeJS.ReadWriteStream {
const resourcesStream = es.through(); // this stream will contain the resources
const bundlesStream = es.through(); // this stream will contain the bundled files
const entryPoints = opts.entryPoints;
if (cjsOpts) {
cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name }));
}
const entryPoints = opts.entryPoints.map(entryPoint => {
if (typeof entryPoint === 'string') {
return { name: path.parse(entryPoint).name };
}
return entryPoint;
});
const allMentionedModules = new Set<string>();
for (const entryPoint of entryPoints) {
@ -198,7 +172,7 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
es.readArray(output.files).pipe(bundlesStream);
// forward all resources
gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
gulp.src(opts.resources ?? [], { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream);
});
const result = es.merge(
@ -211,31 +185,7 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS
sourceRoot: undefined,
addComment: true,
includeContent: true
}))
.pipe(opts.languages && opts.languages.length ? processNlsFiles({
out: opts.src,
fileHeader: opts.header || DEFAULT_FILE_HEADER,
languages: opts.languages
}) : es.through());
}
export interface IOptimizeCommonJSTaskOpts {
/**
* The paths to consider for optimizing.
*/
entryPoints: string[];
/**
* The folder to read files from.
*/
src: string;
/**
* ESBuild `platform` option: https://esbuild.github.io/api/#platform
*/
platform: 'browser' | 'node' | 'neutral';
/**
* ESBuild `external` option: https://esbuild.github.io/api/#external
*/
external: string[];
}));
}
export interface IOptimizeManualTaskOpts {
@ -266,13 +216,9 @@ export interface IOptimizeTaskOpts {
*/
out: string;
/**
* Optimize AMD modules (using our AMD loader).
*/
amd: IOptimizeAMDTaskOpts;
/**
* Optimize CommonJS modules (using esbuild).
*/
commonJS?: IOptimizeCommonJSTaskOpts;
* Optimize ESM modules (using esbuild).
*/
esm: IOptimizeESMTaskOpts;
/**
* Optimize manually by concatenating files.
*/
@ -282,7 +228,7 @@ export interface IOptimizeTaskOpts {
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
return function () {
const optimizers: NodeJS.ReadWriteStream[] = [];
optimizers.push(optimizeESMTask(opts.amd, opts.commonJS));
optimizers.push(optimizeESMTask(opts.esm));
if (opts.manual) {
optimizers.push(optimizeManualTask(opts.manual));

View File

@ -21,11 +21,8 @@ exports.rreddir = rreddir;
exports.ensureDir = ensureDir;
exports.rebase = rebase;
exports.filter = filter;
exports.versionStringToNumber = versionStringToNumber;
exports.streamToPromise = streamToPromise;
exports.getElectronVersion = getElectronVersion;
exports.acquireWebNodePaths = acquireWebNodePaths;
exports.createExternalLoaderConfig = createExternalLoaderConfig;
const es = require("event-stream");
const _debounce = require("debounce");
const _filter = require("gulp-filter");
@ -299,14 +296,6 @@ function filter(fn) {
result.restore = es.through();
return result;
}
function versionStringToNumber(versionStr) {
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
const match = versionStr.match(semverRegex);
if (!match) {
throw new Error('Version string is not properly formatted: ' + versionStr);
}
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
}
function streamToPromise(stream) {
return new Promise((c, e) => {
stream.on('error', err => e(err));
@ -319,68 +308,4 @@ function getElectronVersion() {
const msBuildId = /^ms_build_id="(.*)"$/m.exec(npmrc)[1];
return { electronVersion, msBuildId };
}
function acquireWebNodePaths() {
const root = path.join(__dirname, '..', '..');
const webPackageJSON = path.join(root, '/remote/web', 'package.json');
const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies;
const distroWebPackageJson = path.join(root, '.build/distro/npm/remote/web/package.json');
if (fs.existsSync(distroWebPackageJson)) {
const distroWebPackages = JSON.parse(fs.readFileSync(distroWebPackageJson, 'utf8')).dependencies;
Object.assign(webPackages, distroWebPackages);
}
const nodePaths = {};
for (const key of Object.keys(webPackages)) {
const packageJSON = path.join(root, 'node_modules', key, 'package.json');
const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8'));
// Only cases where the browser is a string are handled
let entryPoint = typeof packageData.browser === 'string' ? packageData.browser : packageData.main;
// On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js
if (!entryPoint) {
// TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint
if (key !== 'jschardet') {
console.warn(`No entry point for ${key} assuming dist/${key}.min.js`);
}
entryPoint = `dist/${key}.min.js`;
}
// Remove any starting path information so it's all relative info
if (entryPoint.startsWith('./')) {
entryPoint = entryPoint.substring(2);
}
else if (entryPoint.startsWith('/')) {
entryPoint = entryPoint.substring(1);
}
// Search for a minified entrypoint as well
if (/(?<!\.min)\.js$/i.test(entryPoint)) {
const minEntryPoint = entryPoint.replace(/\.js$/i, '.min.js');
if (fs.existsSync(path.join(root, 'node_modules', key, minEntryPoint))) {
entryPoint = minEntryPoint;
}
}
nodePaths[key] = entryPoint;
}
// @TODO lramos15 can we make this dynamic like the rest of the node paths
// Add these paths as well for 1DS SDK dependencies.
// Not sure why given the 1DS entrypoint then requires these modules
// they are not fetched from the right location and instead are fetched from out/
nodePaths['@microsoft/dynamicproto-js'] = 'lib/dist/umd/dynamicproto-js.min.js';
nodePaths['@microsoft/applicationinsights-shims'] = 'dist/umd/applicationinsights-shims.min.js';
nodePaths['@microsoft/applicationinsights-core-js'] = 'browser/applicationinsights-core-js.min.js';
return nodePaths;
}
function createExternalLoaderConfig(webEndpoint, commit, quality) {
if (!webEndpoint || !commit || !quality) {
return undefined;
}
webEndpoint = webEndpoint + `/${quality}/${commit}`;
const nodePaths = acquireWebNodePaths();
Object.keys(nodePaths).map(function (key, _) {
nodePaths[key] = `../node_modules/${key}/${nodePaths[key]}`;
});
const externalLoaderConfig = {
baseUrl: `${webEndpoint}/out`,
recordStats: true,
paths: nodePaths
};
return externalLoaderConfig;
}
//# sourceMappingURL=util.js.map

View File

@ -367,16 +367,6 @@ export function filter(fn: (data: any) => boolean): FilterStream {
return result;
}
export function versionStringToNumber(versionStr: string) {
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
const match = versionStr.match(semverRegex);
if (!match) {
throw new Error('Version string is not properly formatted: ' + versionStr);
}
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
}
export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise<void> {
return new Promise((c, e) => {
stream.on('error', err => e(err));
@ -390,83 +380,3 @@ export function getElectronVersion(): Record<string, string> {
const msBuildId = /^ms_build_id="(.*)"$/m.exec(npmrc)![1];
return { electronVersion, msBuildId };
}
export function acquireWebNodePaths() {
const root = path.join(__dirname, '..', '..');
const webPackageJSON = path.join(root, '/remote/web', 'package.json');
const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies;
const distroWebPackageJson = path.join(root, '.build/distro/npm/remote/web/package.json');
if (fs.existsSync(distroWebPackageJson)) {
const distroWebPackages = JSON.parse(fs.readFileSync(distroWebPackageJson, 'utf8')).dependencies;
Object.assign(webPackages, distroWebPackages);
}
const nodePaths: { [key: string]: string } = {};
for (const key of Object.keys(webPackages)) {
const packageJSON = path.join(root, 'node_modules', key, 'package.json');
const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8'));
// Only cases where the browser is a string are handled
let entryPoint: string = typeof packageData.browser === 'string' ? packageData.browser : packageData.main;
// On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js
if (!entryPoint) {
// TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint
if (key !== 'jschardet') {
console.warn(`No entry point for ${key} assuming dist/${key}.min.js`);
}
entryPoint = `dist/${key}.min.js`;
}
// Remove any starting path information so it's all relative info
if (entryPoint.startsWith('./')) {
entryPoint = entryPoint.substring(2);
} else if (entryPoint.startsWith('/')) {
entryPoint = entryPoint.substring(1);
}
// Search for a minified entrypoint as well
if (/(?<!\.min)\.js$/i.test(entryPoint)) {
const minEntryPoint = entryPoint.replace(/\.js$/i, '.min.js');
if (fs.existsSync(path.join(root, 'node_modules', key, minEntryPoint))) {
entryPoint = minEntryPoint;
}
}
nodePaths[key] = entryPoint;
}
// @TODO lramos15 can we make this dynamic like the rest of the node paths
// Add these paths as well for 1DS SDK dependencies.
// Not sure why given the 1DS entrypoint then requires these modules
// they are not fetched from the right location and instead are fetched from out/
nodePaths['@microsoft/dynamicproto-js'] = 'lib/dist/umd/dynamicproto-js.min.js';
nodePaths['@microsoft/applicationinsights-shims'] = 'dist/umd/applicationinsights-shims.min.js';
nodePaths['@microsoft/applicationinsights-core-js'] = 'browser/applicationinsights-core-js.min.js';
return nodePaths;
}
export interface IExternalLoaderInfo {
baseUrl: string;
paths: { [moduleId: string]: string };
[key: string]: any;
}
export function createExternalLoaderConfig(webEndpoint?: string, commit?: string, quality?: string): IExternalLoaderInfo | undefined {
if (!webEndpoint || !commit || !quality) {
return undefined;
}
webEndpoint = webEndpoint + `/${quality}/${commit}`;
const nodePaths = acquireWebNodePaths();
Object.keys(nodePaths).map(function (key, _) {
nodePaths[key] = `../node_modules/${key}/${nodePaths[key]}`;
});
const externalLoaderConfig: IExternalLoaderInfo = {
baseUrl: `${webEndpoint}/out`,
recordStats: true,
paths: nodePaths
};
return externalLoaderConfig;
}