Skip to content

Commit

Permalink
Merge pull request #159300 from microsoft/joh/swc
Browse files Browse the repository at this point in the history
SWC experiments
  • Loading branch information
jrieken authored Sep 1, 2022
2 parents 6815774 + 2f390ce commit 2335d95
Show file tree
Hide file tree
Showing 12 changed files with 382 additions and 9 deletions.
2 changes: 1 addition & 1 deletion build/azure-pipelines/darwin/product-build-darwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ steps:
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp "transpile-client" "transpile-extensions"
yarn gulp "transpile-client-swc" "transpile-extensions"
displayName: Transpile
- ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}:
Expand Down
2 changes: 1 addition & 1 deletion build/azure-pipelines/linux/product-build-linux-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ steps:
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp "transpile-client" "transpile-extensions"
yarn gulp "transpile-client-swc" "transpile-extensions"
displayName: Transpile
- ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}:
Expand Down
2 changes: 1 addition & 1 deletion build/azure-pipelines/win32/product-build-win32.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ steps:
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
exec { yarn gulp "transpile-client" "transpile-extensions" }
exec { yarn gulp "transpile-client-swc" "transpile-extensions" }
displayName: Transpile
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
Expand Down
6 changes: 5 additions & 1 deletion build/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ require('events').EventEmitter.defaultMaxListeners = 100;
const gulp = require('gulp');
const util = require('./lib/util');
const task = require('./lib/task');
const { transpileTask, compileTask, watchTask, compileApiProposalNamesTask, watchApiProposalNamesTask } = require('./lib/compilation');
const { transpileClientSWC, transpileTask, compileTask, watchTask, compileApiProposalNamesTask, watchApiProposalNamesTask } = require('./lib/compilation');
const { monacoTypecheckTask/* , monacoTypecheckWatchTask */ } = require('./gulpfile.editor');
const { compileExtensionsTask, watchExtensionsTask, compileExtensionMediaTask } = require('./gulpfile.extensions');

// API proposal names
gulp.task(compileApiProposalNamesTask);
gulp.task(watchApiProposalNamesTask);

// SWC Client Transpile
const transpileClientSWCTask = task.define('transpile-client-swc', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), transpileClientSWC('src', 'out')));
gulp.task(transpileClientSWCTask);

// Transpile only
const transpileClientTask = task.define('transpile-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), transpileTask('src', 'out')));
gulp.task(transpileClientTask);
Expand Down
24 changes: 23 additions & 1 deletion build/lib/compilation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = exports.transpileTask = void 0;
exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = exports.transpileTask = exports.transpileClientSWC = void 0;
const es = require("event-stream");
const fs = require("fs");
const gulp = require("gulp");
Expand All @@ -18,7 +18,29 @@ const ansiColors = require("ansi-colors");
const os = require("os");
const File = require("vinyl");
const task = require("./task");
const swc_1 = require("./swc");
const watch = require('./watch');
// --- SWC: transpile -------------------------------------
function transpileClientSWC(src, out) {
return function () {
// run SWC sync and put files straight onto the disk
const swcPromise = (0, swc_1.createSwcClientStream)().exec();
// copy none TS resources, like CSS, images, onto the disk
const bom = require('gulp-bom');
const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path));
const tsFilter = util.filter(data => !/\.ts$/.test(data.path));
const srcStream = gulp.src(`${src}/**`, { base: `${src}` });
const copyStream = srcStream
.pipe(utf8Filter)
.pipe(bom()) // this is required to preserve BOM in test files that loose it otherwise
.pipe(utf8Filter.restore)
.pipe(tsFilter);
const copyPromise = util.streamToPromise(copyStream.pipe(gulp.dest(out)));
return Promise.all([swcPromise, copyPromise]);
};
}
exports.transpileClientSWC = transpileClientSWC;
// --- gulp-tsb: compile and transpile --------------------------------
const reporter = (0, reporter_1.createReporter)();
function getTypeScriptCompilerOptions(src) {
const rootDir = path.join(__dirname, `../../${src}`);
Expand Down
33 changes: 32 additions & 1 deletion build/lib/compilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,40 @@ import * as os from 'os';
import ts = require('typescript');
import * as File from 'vinyl';
import * as task from './task';

import { createSwcClientStream } from './swc';
const watch = require('./watch');


// --- SWC: transpile -------------------------------------

export function transpileClientSWC(src: string, out: string) {

return function () {

// run SWC sync and put files straight onto the disk
const swcPromise = createSwcClientStream().exec();

// copy none TS resources, like CSS, images, onto the disk
const bom = require('gulp-bom') as typeof import('gulp-bom');
const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path));
const tsFilter = util.filter(data => !/\.ts$/.test(data.path));
const srcStream = gulp.src(`${src}/**`, { base: `${src}` });

const copyStream = srcStream
.pipe(utf8Filter)
.pipe(bom()) // this is required to preserve BOM in test files that loose it otherwise
.pipe(utf8Filter.restore)
.pipe(tsFilter);

const copyPromise = util.streamToPromise(copyStream.pipe(gulp.dest(out)));

return Promise.all([swcPromise, copyPromise]);
};

}

// --- gulp-tsb: compile and transpile --------------------------------

const reporter = createReporter();

function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions {
Expand Down
22 changes: 22 additions & 0 deletions build/lib/swc/.swcrc-amd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json.schemastore.org/swcrc",
"exclude": "\\.js$",
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2020",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "amd",
"noInterop": true
},
"minify": false
}
22 changes: 22 additions & 0 deletions build/lib/swc/.swcrc-no-mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json.schemastore.org/swcrc",
"exclude": "\\.js$",
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2020",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"isModule": false,
"module": {
"type": "es6"
},
"minify": false
}
74 changes: 74 additions & 0 deletions build/lib/swc/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSwcClientStream = void 0;
const child_process_1 = require("child_process");
const stream_1 = require("stream");
const path_1 = require("path");
const util = require("util");
const gulp = require("gulp");
/**
* SWC transpile stream. Can be used as stream but `exec` is the prefered way because under the
* hood this simply shells out to swc-cli. There is room for improvement but this already works.
* Ideas
* * use API, not swc-cli
* * invoke binaries directly, don't go through swc-cli
* * understand how to configure both setups in one (https://github.com/swc-project/swc/issues/4989)
*/
function createSwcClientStream() {
const execAsync = util.promisify(child_process_1.exec);
const cwd = (0, path_1.join)(__dirname, '../../../');
const srcDir = (0, path_1.join)(__dirname, '../../../src');
const outDir = (0, path_1.join)(__dirname, '../../../out');
const pathConfigAmd = (0, path_1.join)(__dirname, '.swcrc-amd');
const pathConfigNoModule = (0, path_1.join)(__dirname, '.swcrc-no-mod');
return new class extends stream_1.Readable {
constructor() {
super({ objectMode: true, highWaterMark: Number.MAX_SAFE_INTEGER });
this._isStarted = false;
}
async exec(print) {
const t1 = Date.now();
const errors = [];
try {
const data1 = await execAsync(`npx swc --config-file ${pathConfigAmd} ${srcDir}/ --out-dir ${outDir}`, { encoding: 'utf-8', cwd });
errors.push(data1.stderr);
const data2 = await execAsync(`npx swc --config-file ${pathConfigNoModule} ${srcDir}/vs/base/worker/workerMain.ts --out-dir ${outDir}`, { encoding: 'utf-8', cwd });
errors.push(data2.stderr);
return true;
}
catch (error) {
console.error(errors);
console.error(error);
this.destroy(error);
return false;
}
finally {
if (print) {
console.log(`DONE with SWC after ${Date.now() - t1}ms`);
}
}
}
async _read(_size) {
if (this._isStarted) {
return;
}
this._isStarted = true;
if (!this.exec()) {
this.push(null);
return;
}
for await (const file of gulp.src(`${outDir}/**/*.js`, { base: outDir })) {
this.push(file);
}
this.push(null);
}
};
}
exports.createSwcClientStream = createSwcClientStream;
if (process.argv[1] === __filename) {
createSwcClientStream().exec(true);
}
80 changes: 80 additions & 0 deletions build/lib/swc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { exec } from 'child_process';
import { Readable } from 'stream';
import { join } from 'path';
import * as util from 'util';
import * as gulp from 'gulp';

/**
* SWC transpile stream. Can be used as stream but `exec` is the prefered way because under the
* hood this simply shells out to swc-cli. There is room for improvement but this already works.
* Ideas
* * use API, not swc-cli
* * invoke binaries directly, don't go through swc-cli
* * understand how to configure both setups in one (https://github.com/swc-project/swc/issues/4989)
*/
export function createSwcClientStream(): Readable & { exec(print?: boolean): Promise<boolean> } {

const execAsync = util.promisify(exec);

const cwd = join(__dirname, '../../../');
const srcDir = join(__dirname, '../../../src');
const outDir = join(__dirname, '../../../out');

const pathConfigAmd = join(__dirname, '.swcrc-amd');
const pathConfigNoModule = join(__dirname, '.swcrc-no-mod');

return new class extends Readable {

private _isStarted = false;

constructor() {
super({ objectMode: true, highWaterMark: Number.MAX_SAFE_INTEGER });
}

async exec(print?: boolean) {
const t1 = Date.now();
const errors: string[] = [];
try {
const data1 = await execAsync(`npx swc --config-file ${pathConfigAmd} ${srcDir}/ --out-dir ${outDir}`, { encoding: 'utf-8', cwd });
errors.push(data1.stderr);

const data2 = await execAsync(`npx swc --config-file ${pathConfigNoModule} ${srcDir}/vs/base/worker/workerMain.ts --out-dir ${outDir}`, { encoding: 'utf-8', cwd });
errors.push(data2.stderr);
return true;
} catch (error) {
console.error(errors);
console.error(error);
this.destroy(error);
return false;
} finally {
if (print) {
console.log(`DONE with SWC after ${Date.now() - t1}ms`);
}
}
}

async _read(_size: number): Promise<void> {
if (this._isStarted) {
return;
}
this._isStarted = true;
if (!this.exec()) {
this.push(null);
return;
}
for await (const file of gulp.src(`${outDir}/**/*.js`, { base: outDir })) {
this.push(file);
}
this.push(null);
}
};
}

if (process.argv[1] === __filename) {
createSwcClientStream().exec(true);
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
"devDependencies": {
"7zip": "0.0.6",
"@playwright/test": "1.24.2",
"@swc/cli": "0.1.57",
"@swc/core": "1.2.245",
"@types/cookie": "^0.3.3",
"@types/copy-webpack-plugin": "^6.0.3",
"@types/cssnano": "^4.0.0",
Expand Down
Loading

0 comments on commit 2335d95

Please sign in to comment.