Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/gulpfile.extensions.ts
5243 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
// Increase max listeners for event emitters
7
import { EventEmitter } from 'events';
8
EventEmitter.defaultMaxListeners = 100;
9
10
import es from 'event-stream';
11
import glob from 'glob';
12
import gulp from 'gulp';
13
import filter from 'gulp-filter';
14
import plumber from 'gulp-plumber';
15
import sourcemaps from 'gulp-sourcemaps';
16
import * as path from 'path';
17
import * as nodeUtil from 'util';
18
import * as ext from './lib/extensions.ts';
19
import { getVersion } from './lib/getVersion.ts';
20
import { createReporter } from './lib/reporter.ts';
21
import * as task from './lib/task.ts';
22
import * as tsb from './lib/tsb/index.ts';
23
import { createTsgoStream, spawnTsgo } from './lib/tsgo.ts';
24
import * as util from './lib/util.ts';
25
import watcher from './lib/watch/index.ts';
26
27
const root = path.dirname(import.meta.dirname);
28
const commit = getVersion(root);
29
30
// To save 250ms for each gulp startup, we are caching the result here
31
// const compilations = glob.sync('**/tsconfig.json', {
32
// cwd: extensionsPath,
33
// ignore: ['**/out/**', '**/node_modules/**']
34
// });
35
const compilations = [
36
'extensions/configuration-editing/tsconfig.json',
37
'extensions/css-language-features/client/tsconfig.json',
38
'extensions/css-language-features/server/tsconfig.json',
39
'extensions/debug-auto-launch/tsconfig.json',
40
'extensions/debug-server-ready/tsconfig.json',
41
'extensions/emmet/tsconfig.json',
42
'extensions/extension-editing/tsconfig.json',
43
'extensions/git/tsconfig.json',
44
'extensions/git-base/tsconfig.json',
45
'extensions/github/tsconfig.json',
46
'extensions/github-authentication/tsconfig.json',
47
'extensions/grunt/tsconfig.json',
48
'extensions/gulp/tsconfig.json',
49
'extensions/html-language-features/client/tsconfig.json',
50
'extensions/html-language-features/server/tsconfig.json',
51
'extensions/ipynb/tsconfig.json',
52
'extensions/jake/tsconfig.json',
53
'extensions/json-language-features/client/tsconfig.json',
54
'extensions/json-language-features/server/tsconfig.json',
55
'extensions/markdown-language-features/tsconfig.json',
56
'extensions/markdown-math/tsconfig.json',
57
'extensions/media-preview/tsconfig.json',
58
'extensions/merge-conflict/tsconfig.json',
59
'extensions/mermaid-chat-features/tsconfig.json',
60
'extensions/terminal-suggest/tsconfig.json',
61
'extensions/microsoft-authentication/tsconfig.json',
62
'extensions/notebook-renderers/tsconfig.json',
63
'extensions/npm/tsconfig.json',
64
'extensions/php-language-features/tsconfig.json',
65
'extensions/references-view/tsconfig.json',
66
'extensions/search-result/tsconfig.json',
67
'extensions/simple-browser/tsconfig.json',
68
'extensions/tunnel-forwarding/tsconfig.json',
69
'extensions/typescript-language-features/web/tsconfig.json',
70
'extensions/typescript-language-features/tsconfig.json',
71
'extensions/vscode-api-tests/tsconfig.json',
72
'extensions/vscode-colorize-tests/tsconfig.json',
73
'extensions/vscode-colorize-perf-tests/tsconfig.json',
74
'extensions/vscode-test-resolver/tsconfig.json',
75
76
'.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json',
77
'.vscode/extensions/vscode-selfhost-import-aid/tsconfig.json',
78
];
79
80
const getBaseUrl = (out: string) => `https://main.vscode-cdn.net/sourcemaps/${commit}/${out}`;
81
82
function rewriteTsgoSourceMappingUrlsIfNeeded(build: boolean, out: string, baseUrl: string): Promise<void> {
83
if (!build) {
84
return Promise.resolve();
85
}
86
87
return util.streamToPromise(
88
gulp.src(path.join(out, '**', '*.js'), { base: out })
89
.pipe(util.rewriteSourceMappingURL(baseUrl))
90
.pipe(gulp.dest(out))
91
);
92
}
93
94
const tasks = compilations.map(function (tsconfigFile) {
95
const absolutePath = path.join(root, tsconfigFile);
96
const relativeDirname = path.dirname(tsconfigFile.replace(/^(.*\/)?extensions\//i, ''));
97
98
const overrideOptions: { sourceMap?: boolean; inlineSources?: boolean; base?: string } = {};
99
overrideOptions.sourceMap = true;
100
101
const name = relativeDirname.replace(/\//g, '-');
102
103
const srcRoot = path.dirname(tsconfigFile);
104
const srcBase = path.join(srcRoot, 'src');
105
const src = path.join(srcBase, '**');
106
const srcOpts = { cwd: root, base: srcBase, dot: true };
107
108
const out = path.join(srcRoot, 'out');
109
const baseUrl = getBaseUrl(out);
110
111
function createPipeline(build: boolean, emitError?: boolean, transpileOnly?: boolean) {
112
const reporter = createReporter('extensions');
113
114
overrideOptions.inlineSources = Boolean(build);
115
overrideOptions.base = path.dirname(absolutePath);
116
117
const compilation = tsb.create(absolutePath, overrideOptions, { verbose: false, transpileOnly, transpileOnlyIncludesDts: transpileOnly, transpileWithEsbuild: true }, err => reporter(err.toString()));
118
119
const pipeline = function () {
120
const input = es.through();
121
const tsFilter = filter(['**/*.ts', '!**/lib/lib*.d.ts', '!**/node_modules/**'], { restore: true, dot: true });
122
const output = input
123
.pipe(plumber({
124
errorHandler: function (err) {
125
if (err && !err.__reporter__) {
126
reporter(err);
127
}
128
}
129
}))
130
.pipe(tsFilter)
131
.pipe(util.loadSourcemaps())
132
.pipe(compilation())
133
.pipe(build ? util.stripSourceMappingURL() : es.through())
134
.pipe(sourcemaps.write('.', {
135
sourceMappingURL: !build ? undefined : f => `${baseUrl}/${f.relative}.map`,
136
addComment: !!build,
137
includeContent: !!build,
138
// note: trailing slash is important, else the source URLs in V8's file coverage are incorrect
139
sourceRoot: '../src/',
140
}))
141
.pipe(tsFilter.restore)
142
.pipe(reporter.end(!!emitError));
143
144
return es.duplex(input, output);
145
};
146
147
// add src-stream for project files
148
pipeline.tsProjectSrc = () => {
149
return compilation.src(srcOpts);
150
};
151
return pipeline;
152
}
153
154
const cleanTask = task.define(`clean-extension-${name}`, util.rimraf(out));
155
156
const transpileTask = task.define(`transpile-extension:${name}`, task.series(cleanTask, () => {
157
const pipeline = createPipeline(false, true, true);
158
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
159
const input = es.merge(nonts, pipeline.tsProjectSrc());
160
161
return input
162
.pipe(pipeline())
163
.pipe(gulp.dest(out));
164
}));
165
166
const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, async () => {
167
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'], { dot: true }));
168
const copyNonTs = util.streamToPromise(nonts.pipe(gulp.dest(out)));
169
const tsgo = spawnTsgo(absolutePath, () => rewriteTsgoSourceMappingUrlsIfNeeded(false, out, baseUrl));
170
171
await Promise.all([copyNonTs, tsgo]);
172
}));
173
174
const watchTask = task.define(`watch-extension:${name}`, task.series(cleanTask, () => {
175
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'], { dot: true }));
176
const watchInput = watcher(src, { ...srcOpts, ...{ readDelay: 200 } });
177
const watchNonTs = watchInput.pipe(filter(['**', '!**/*.ts'], { dot: true })).pipe(gulp.dest(out));
178
const tsgoStream = watchInput.pipe(util.debounce(() => createTsgoStream(absolutePath, () => rewriteTsgoSourceMappingUrlsIfNeeded(false, out, baseUrl)), 200));
179
const watchStream = es.merge(nonts.pipe(gulp.dest(out)), watchNonTs, tsgoStream);
180
181
return watchStream;
182
}));
183
184
// Tasks
185
gulp.task(transpileTask);
186
gulp.task(compileTask);
187
gulp.task(watchTask);
188
189
return { transpileTask, compileTask, watchTask };
190
});
191
192
const transpileExtensionsTask = task.define('transpile-extensions', task.parallel(...tasks.map(t => t.transpileTask)));
193
gulp.task(transpileExtensionsTask);
194
195
export const compileExtensionsTask = task.define('compile-extensions', task.parallel(...tasks.map(t => t.compileTask)));
196
gulp.task(compileExtensionsTask);
197
198
export const watchExtensionsTask = task.define('watch-extensions', task.parallel(...tasks.map(t => t.watchTask)));
199
gulp.task(watchExtensionsTask);
200
201
//#region Extension media
202
203
export const compileExtensionMediaTask = task.define('compile-extension-media', () => ext.buildExtensionMedia(false));
204
gulp.task(compileExtensionMediaTask);
205
206
export const watchExtensionMedia = task.define('watch-extension-media', () => ext.buildExtensionMedia(true));
207
gulp.task(watchExtensionMedia);
208
209
export const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => ext.buildExtensionMedia(false, '.build/extensions'));
210
gulp.task(compileExtensionMediaBuildTask);
211
212
//#endregion
213
214
//#region Azure Pipelines
215
216
/**
217
* Cleans the build directory for extensions
218
*/
219
export const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions'));
220
221
/**
222
* brings in the marketplace extensions for the build
223
*/
224
const bundleMarketplaceExtensionsBuildTask = task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build')));
225
226
/**
227
* Compiles the non-native extensions for the build
228
* @note this does not clean the directory ahead of it. See {@link cleanExtensionsBuildTask} for that.
229
*/
230
export const compileNonNativeExtensionsBuildTask = task.define('compile-non-native-extensions-build', task.series(
231
bundleMarketplaceExtensionsBuildTask,
232
task.define('bundle-non-native-extensions-build', () => ext.packageNonNativeLocalExtensionsStream(false, false).pipe(gulp.dest('.build')))
233
));
234
gulp.task(compileNonNativeExtensionsBuildTask);
235
236
/**
237
* Compiles the native extensions for the build
238
* @note this does not clean the directory ahead of it. See {@link cleanExtensionsBuildTask} for that.
239
*/
240
export const compileNativeExtensionsBuildTask = task.define('compile-native-extensions-build', () => ext.packageNativeLocalExtensionsStream(false, false).pipe(gulp.dest('.build')));
241
gulp.task(compileNativeExtensionsBuildTask);
242
243
/**
244
* Compiles the extensions for the build.
245
* This is essentially a helper task that combines {@link cleanExtensionsBuildTask}, {@link compileNonNativeExtensionsBuildTask} and {@link compileNativeExtensionsBuildTask}
246
*/
247
export const compileAllExtensionsBuildTask = task.define('compile-extensions-build', task.series(
248
cleanExtensionsBuildTask,
249
bundleMarketplaceExtensionsBuildTask,
250
task.define('bundle-extensions-build', () => ext.packageAllLocalExtensionsStream(false, false).pipe(gulp.dest('.build'))),
251
));
252
gulp.task(compileAllExtensionsBuildTask);
253
254
// This task is run in the compilation stage of the CI pipeline. We only compile the non-native extensions since those can be fully built regardless of platform.
255
// This defers the native extensions to the platform specific stage of the CI pipeline.
256
gulp.task(task.define('extensions-ci', task.series(compileNonNativeExtensionsBuildTask, compileExtensionMediaBuildTask)));
257
258
const compileExtensionsBuildPullRequestTask = task.define('compile-extensions-build-pr', task.series(
259
cleanExtensionsBuildTask,
260
bundleMarketplaceExtensionsBuildTask,
261
task.define('bundle-extensions-build-pr', () => ext.packageAllLocalExtensionsStream(false, true).pipe(gulp.dest('.build'))),
262
));
263
gulp.task(compileExtensionsBuildPullRequestTask);
264
265
// This task is run in the compilation stage of the PR pipeline. We compile all extensions in it to verify compilation.
266
gulp.task(task.define('extensions-ci-pr', task.series(compileExtensionsBuildPullRequestTask, compileExtensionMediaBuildTask)));
267
268
//#endregion
269
270
export const compileWebExtensionsTask = task.define('compile-web', () => buildWebExtensions(false));
271
gulp.task(compileWebExtensionsTask);
272
273
export const watchWebExtensionsTask = task.define('watch-web', () => buildWebExtensions(true));
274
gulp.task(watchWebExtensionsTask);
275
276
async function buildWebExtensions(isWatch: boolean) {
277
const extensionsPath = path.join(root, 'extensions');
278
const webpackConfigLocations = await nodeUtil.promisify(glob)(
279
path.join(extensionsPath, '**', 'extension-browser.webpack.config.js'),
280
{ ignore: ['**/node_modules'] }
281
);
282
return ext.webpackExtensions('packaging web extension', isWatch, webpackConfigLocations.map(configPath => ({ configPath })));
283
}
284
285