debt - use esbuild for CSS minification (#250820)

This commit is contained in:
Benjamin Pasero
2025-06-06 12:04:01 +02:00
committed by GitHub
parent d49ebe603c
commit 1330a32f25
13 changed files with 20 additions and 1102 deletions

View File

@@ -257,7 +257,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
const src = gulp.src(sourceFolderName + '/**', { base: '.' })
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); }))
.pipe(util.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
.pipe(filter(['**', '!**/*.{js,css}.map']));
const workspaceExtensionPoints = ['debuggers', 'jsonValidation'];
const isUIExtension = (manifest) => {
@@ -298,7 +298,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
const extensions = gulp.src(extensionPaths, { base: '.build', dot: true });
const extensionsCommonDependencies = gulp.src('.build/extensions/node_modules/**', { base: '.build', dot: true });
const sources = es.merge(src, extensions, extensionsCommonDependencies)
.pipe(filter(['**', '!**/*.js.map'], { dot: true }));
.pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true }));
let version = packageJson.version;
const quality = product.quality;
@@ -333,7 +333,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
const dependenciesSrc = productionDependencies.map(d => path.relative(REPO_ROOT, d)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`]).flat();
const deps = gulp.src(dependenciesSrc, { base: 'remote', dot: true })
// filter out unnecessary files, no source maps in server build
.pipe(filter(['**', '!**/package-lock.json', '!**/*.js.map']))
.pipe(filter(['**', '!**/package-lock.json', '!**/*.{js,css}.map']))
.pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore')))
.pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`)))
.pipe(jsFilter)

View File

@@ -244,7 +244,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const extensions = gulp.src(['.build/extensions/**', ...platformSpecificBuiltInExtensionsExclusions], { base: '.build', dot: true });
const sources = es.merge(src, extensions)
.pipe(filter(['**', '!**/*.js.map'], { dot: true }));
.pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true }));
let version = packageJson.version;
const quality = product.quality;
@@ -289,7 +289,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const dependenciesSrc = productionDependencies.map(d => path.relative(root, d)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]).flat().concat('!**/*.mk');
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true })
.pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.js.map']))
.pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.{js,css}.map']))
.pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore')))
.pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`)))
.pipe(jsFilter)

View File

@@ -152,7 +152,7 @@ function packageTask(sourceFolderName, destinationFolderName) {
const loader = gulp.src('build/loader.min', { base: 'build', dot: true }).pipe(rename('out/vs/loader.js')); // TODO@esm remove line when we stop supporting web-amd-esm-bridge
const sources = es.merge(src, extensions, loader)
.pipe(filter(['**', '!**/*.js.map'], { dot: true }))
.pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true }))
// TODO@esm remove me once we stop supporting our web-esm-bridge
.pipe(es.through(function (file) {
if (file.relative === 'out/vs/workbench/workbench.web.main.internal.css') {

View File

@@ -59,7 +59,6 @@ const os_1 = __importDefault(require("os"));
const vinyl_1 = __importDefault(require("vinyl"));
const task = __importStar(require("./task"));
const index_1 = require("./mangle/index");
const postcss_1 = require("./postcss");
const ts = require("typescript");
const watch = require('./watch');
// --- gulp-tsb: compile and transpile --------------------------------
@@ -96,14 +95,11 @@ function createCompile(src, { build, emitError, transpileOnly, preserveEnglish }
const tsFilter = util.filter(data => /\.ts$/.test(data.path));
const isUtf8Test = (f) => /(\/|\\)test(\/|\\).*utf8/.test(f.path);
const isRuntimeJs = (f) => f.path.endsWith('.js') && !f.path.includes('fixtures');
const isCSS = (f) => f.path.endsWith('.css') && !f.path.includes('fixtures');
const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path)));
const postcssNesting = require('postcss-nesting');
const input = event_stream_1.default.through();
const output = input
.pipe(util.$if(isUtf8Test, bom())) // this is required to preserve BOM in test files that loose it otherwise
.pipe(util.$if(!build && isRuntimeJs, util.appendOwnPathSourceURL()))
.pipe(util.$if(isCSS, (0, postcss_1.gulpPostcss)([postcssNesting()], err => reporter(String(err)))))
.pipe(tsFilter)
.pipe(util.loadSourcemaps())
.pipe(compilation(token))

View File

@@ -18,7 +18,6 @@ import File from 'vinyl';
import * as task from './task';
import { Mangler } from './mangle/index';
import { RawSourceMap } from 'source-map';
import { gulpPostcss } from './postcss';
import ts = require('typescript');
const watch = require('./watch');
@@ -72,16 +71,12 @@ export function createCompile(src: string, { build, emitError, transpileOnly, pr
const tsFilter = util.filter(data => /\.ts$/.test(data.path));
const isUtf8Test = (f: File) => /(\/|\\)test(\/|\\).*utf8/.test(f.path);
const isRuntimeJs = (f: File) => f.path.endsWith('.js') && !f.path.includes('fixtures');
const isCSS = (f: File) => f.path.endsWith('.css') && !f.path.includes('fixtures');
const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path)));
const postcssNesting = require('postcss-nesting');
const input = es.through();
const output = input
.pipe(util.$if(isUtf8Test, bom())) // this is required to preserve BOM in test files that loose it otherwise
.pipe(util.$if(!build && isRuntimeJs, util.appendOwnPathSourceURL()))
.pipe(util.$if(isCSS, gulpPostcss([postcssNesting()], err => reporter(String(err)))))
.pipe(tsFilter)
.pipe(util.loadSourcemaps())
.pipe(compilation(token))

View File

@@ -251,8 +251,6 @@ function isNameTakenInFile(node, name) {
return false;
}
const skippedExportMangledFiles = [
// Build
'css.build',
// Monaco
'editorCommon',
'editorOptions',

View File

@@ -280,8 +280,6 @@ function isNameTakenInFile(node: ts.Node, name: string): boolean {
}
const skippedExportMangledFiles = [
// Build
'css.build',
// Monaco
'editorCommon',

View File

@@ -50,7 +50,6 @@ const fs_1 = __importDefault(require("fs"));
const pump_1 = __importDefault(require("pump"));
const vinyl_1 = __importDefault(require("vinyl"));
const bundle = __importStar(require("./bundle"));
const postcss_1 = require("./postcss");
const esbuild_1 = __importDefault(require("esbuild"));
const gulp_sourcemaps_1 = __importDefault(require("gulp-sourcemaps"));
const fancy_log_1 = __importDefault(require("fancy-log"));
@@ -187,12 +186,10 @@ function bundleTask(opts) {
function minifyTask(src, sourceMapBaseUrl) {
const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
return cb => {
const cssnano = require('cssnano');
const svgmin = require('gulp-svgmin');
const jsFilter = (0, gulp_filter_1.default)('**/*.js', { restore: true });
const cssFilter = (0, gulp_filter_1.default)('**/*.css', { restore: true });
const esbuildFilter = (0, gulp_filter_1.default)('**/*.{js,css}', { restore: true });
const svgFilter = (0, gulp_filter_1.default)('**/*.svg', { restore: true });
(0, pump_1.default)(gulp_1.default.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, gulp_sourcemaps_1.default.init({ loadMaps: true }), event_stream_1.default.map((f, cb) => {
(0, pump_1.default)(gulp_1.default.src([src + '/**', '!' + src + '/**/*.map']), esbuildFilter, gulp_sourcemaps_1.default.init({ loadMaps: true }), event_stream_1.default.map((f, cb) => {
esbuild_1.default.build({
entryPoints: [f.path],
minify: true,
@@ -201,11 +198,11 @@ function minifyTask(src, sourceMapBaseUrl) {
packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages
platform: 'neutral', // makes esm
target: ['es2022'],
write: false
write: false,
}).then(res => {
const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path));
const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path));
const contents = Buffer.from(jsFile.contents);
const jsOrCSSFile = res.outputFiles.find(f => /\.(js|css)$/.test(f.path));
const sourceMapFile = res.outputFiles.find(f => /\.(js|css)\.map$/.test(f.path));
const contents = Buffer.from(jsOrCSSFile.contents);
const unicodeMatch = contents.toString().match(/[^\x00-\xFF]+/g);
if (unicodeMatch) {
cb(new Error(`Found non-ascii character ${unicodeMatch[0]} in the minified output of ${f.path}. Non-ASCII characters in the output can cause performance problems when loading. Please review if you have introduced a regular expression that esbuild is not automatically converting and convert it to using unicode escape sequences.`));
@@ -216,7 +213,7 @@ function minifyTask(src, sourceMapBaseUrl) {
cb(undefined, f);
}
}, cb);
}), jsFilter.restore, cssFilter, (0, postcss_1.gulpPostcss)([cssnano({ preset: 'default' })]), cssFilter.restore, svgFilter, svgmin(), svgFilter.restore, gulp_sourcemaps_1.default.write('./', {
}), esbuildFilter.restore, svgFilter, svgmin(), svgFilter.restore, gulp_sourcemaps_1.default.write('./', {
sourceMappingURL,
sourceRoot: undefined,
includeContent: true,

View File

@@ -11,7 +11,6 @@ import fs from 'fs';
import pump from 'pump';
import VinylFile from 'vinyl';
import * as bundle from './bundle';
import { gulpPostcss } from './postcss';
import esbuild from 'esbuild';
import sourcemaps from 'gulp-sourcemaps';
import fancyLog from 'fancy-log';
@@ -213,16 +212,14 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) =>
const sourceMappingURL = sourceMapBaseUrl ? ((f: any) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
return cb => {
const cssnano = require('cssnano') as typeof import('cssnano');
const svgmin = require('gulp-svgmin') as typeof import('gulp-svgmin');
const jsFilter = filter('**/*.js', { restore: true });
const cssFilter = filter('**/*.css', { restore: true });
const esbuildFilter = filter('**/*.{js,css}', { restore: true });
const svgFilter = filter('**/*.svg', { restore: true });
pump(
gulp.src([src + '/**', '!' + src + '/**/*.map']),
jsFilter,
esbuildFilter,
sourcemaps.init({ loadMaps: true }),
es.map((f: any, cb) => {
esbuild.build({
@@ -233,12 +230,12 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) =>
packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages
platform: 'neutral', // makes esm
target: ['es2022'],
write: false
write: false,
}).then(res => {
const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!;
const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path))!;
const jsOrCSSFile = res.outputFiles.find(f => /\.(js|css)$/.test(f.path))!;
const sourceMapFile = res.outputFiles.find(f => /\.(js|css)\.map$/.test(f.path))!;
const contents = Buffer.from(jsFile.contents);
const contents = Buffer.from(jsOrCSSFile.contents);
const unicodeMatch = contents.toString().match(/[^\x00-\xFF]+/g);
if (unicodeMatch) {
cb(new Error(`Found non-ascii character ${unicodeMatch[0]} in the minified output of ${f.path}. Non-ASCII characters in the output can cause performance problems when loading. Please review if you have introduced a regular expression that esbuild is not automatically converting and convert it to using unicode escape sequences.`));
@@ -250,10 +247,7 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) =>
}
}, cb);
}),
jsFilter.restore,
cssFilter,
gulpPostcss([cssnano({ preset: 'default' })]),
cssFilter.restore,
esbuildFilter.restore,
svgFilter,
svgmin(),
svgFilter.restore,

View File

@@ -1,39 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.gulpPostcss = gulpPostcss;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const postcss_1 = __importDefault(require("postcss"));
const event_stream_1 = __importDefault(require("event-stream"));
function gulpPostcss(plugins, handleError) {
const instance = (0, postcss_1.default)(plugins);
return event_stream_1.default.map((file, callback) => {
if (file.isNull()) {
return callback(null, file);
}
if (file.isStream()) {
return callback(new Error('Streaming not supported'));
}
instance
.process(file.contents.toString(), { from: file.path })
.then((result) => {
file.contents = Buffer.from(result.css);
callback(null, file);
})
.catch((error) => {
if (handleError) {
handleError(error);
callback();
}
else {
callback(error);
}
});
});
}
//# sourceMappingURL=postcss.js.map

View File

@@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import postcss from 'postcss';
import File from 'vinyl';
import es from 'event-stream';
export function gulpPostcss(plugins: postcss.AcceptedPlugin[], handleError?: (err: Error) => void) {
const instance = postcss(plugins);
return es.map((file: File, callback: (error?: any, file?: any) => void) => {
if (file.isNull()) {
return callback(null, file);
}
if (file.isStream()) {
return callback(new Error('Streaming not supported'));
}
instance
.process(file.contents.toString(), { from: file.path })
.then((result) => {
file.contents = Buffer.from(result.css);
callback(null, file);
})
.catch((error) => {
if (handleError) {
handleError(error);
callback();
} else {
callback(error);
}
});
});
}

982
build/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,6 @@
"@vscode/ripgrep": "^1.15.10",
"@vscode/vsce": "2.20.1",
"byline": "^5.0.0",
"cssnano": "^7.0.7",
"debug": "^4.3.2",
"electron-osx-sign": "^0.4.16",
"esbuild": "0.25.0",
@@ -49,8 +48,6 @@
"jsonc-parser": "^2.3.0",
"jws": "^4.0.0",
"mime": "^1.4.1",
"postcss": "^8.5.3",
"postcss-nesting": "^13.0.1",
"source-map": "0.6.1",
"ternary-stream": "^3.0.0",
"through2": "^4.0.2",