Skip to content

Commit

Permalink
feat: improve build system and reduce load time of extension on start…
Browse files Browse the repository at this point in the history
…up by 40%

This change introduces ESBuild as optimization step in the webpack build, this reduces the bundle size and minimizes the code. The optimized bundle loads faster and overall performance a better. This change applies to the end-user Vlocode VSCode extension and the vlocode deployment CLI.
  • Loading branch information
Codeneos committed Aug 20, 2023
1 parent 01ddc01 commit 692de00
Show file tree
Hide file tree
Showing 48 changed files with 223 additions and 177 deletions.
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ module.exports = {
"packages/vscode-extension"
],
transform: {
'^.+\\.ts$': ['ts-jest', { isolatedModules: true }]
'^.+\\.ts$': ['ts-jest', { isolatedModules: true, esModuleInterop: true }]
}
};
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"@vlocode/vlocity-deploy": "workspace:*",
"chalk": "^4.1.1",
"commander": "^9.2.0",
"esbuild-loader": "^4.0.1",
"fs-extra": "^9.0",
"glob": "^7.1.7",
"jest": "^29.6.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/activate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Logger, LogManager, FileSystem } from '@vlocode/core';
import { OmniScriptActivator, OmniScriptVersionDetail, ScriptDefinitionProvider, OmniScriptLookupService } from '@vlocode/omniscript';
import { Argument, Option } from '../command';
import * as logSymbols from 'log-symbols';
import logSymbols from 'log-symbols';
import { forEachAsyncParallel, getErrorMessage, groupBy, isSalesforceId, Iterable, sortBy, Timer } from '@vlocode/util';
import { SalesforceCommand } from '../salesforceCommand';

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as logSymbols from 'log-symbols';
import logSymbols from 'log-symbols';
import { join } from 'path';
import * as chalk from 'chalk';
import chalk from 'chalk';
import { existsSync } from 'fs';

import { Logger, LogLevel, LogManager } from '@vlocode/core';
Expand Down
21 changes: 0 additions & 21 deletions packages/cli/webpack/plugins/watchMarkers.ts

This file was deleted.

76 changes: 42 additions & 34 deletions packages/cli/webpack/webpack.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import * as path from 'path';
import * as glob from 'glob';
import glob from 'glob';
import * as webpack from 'webpack';
import WatchMarkersPlugin from './plugins/watchMarkers';
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
import type { Options } from 'ts-loader';
import * as packageJson from '../package.json';
import packageJson from '../package.json';
import { existsSync, readFileSync, readdirSync } from 'fs';
import { EsbuildPlugin } from 'esbuild-loader';

const packageExternals = [
'vscode',
'vscode-languageclient',
'electron'
'electron',
'utf-8-validate',
'bufferutil'
];

const contextFolder = path.resolve(__dirname, '..');
const workspaceFolder = path.resolve(contextFolder, '..');
const workspacePackages = readdirSync(workspaceFolder, { withFileTypes: true })
.filter(p => p.isDirectory() && existsSync(path.join(workspaceFolder, p.name, 'package.json')))
.map(p => ({
name: p.name,
dir: path.join(workspaceFolder, p.name),
packageJson: JSON.parse(readFileSync(path.join(workspaceFolder, p.name, 'package.json')).toString())
}));

const common : webpack.Configuration = {
name: 'vlocode-cli',
Expand All @@ -36,33 +44,25 @@ const common : webpack.Configuration = {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
compilerOptions: {
sourceMap: false,
rootDir: undefined,
outDir: path.resolve(contextFolder, '.ts-temp')
},
transpileOnly: true,
configFile: 'tsconfig.json'
} as Options
configFile: path.resolve(__dirname, 'tsconfig.json'),
transpileOnly: process.env.CI == 'true' || process.env.CIRCLECI == 'true'
}
}],
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.html', '.json', '.yaml'],
alias: {
'@vlocode/core': path.resolve(workspaceFolder, 'core', 'src', 'index.ts'),
'@vlocode/salesforce': path.resolve(workspaceFolder, 'salesforce', 'src', 'index.ts'),
'@vlocode/util': path.resolve(workspaceFolder, 'util', 'src', 'index.ts'),
'@vlocode/vlocity-deploy': path.resolve(workspaceFolder, 'vlocity-deploy', 'src', 'index.ts')
},
plugins: [
new TsconfigPathsPlugin()
]
extensions: ['.ts', '.js', '.json', '.yaml'],
alias: Object.fromEntries(
workspacePackages.map(({ dir, packageJson }) => ([
packageJson.name,
path.join(dir, 'src')
]))
)
},
output: {
filename: '[name].js',
Expand All @@ -76,7 +76,6 @@ const common : webpack.Configuration = {
__filename: false
},
optimization: {
minimize: false,
runtimeChunk: false,
concatenateModules: true,
mergeDuplicateChunks: true,
Expand All @@ -87,32 +86,41 @@ const common : webpack.Configuration = {
usedExports: false,
portableRecords: true,
splitChunks: false,
minimize: true,
minimizer: [
new EsbuildPlugin({
target: 'es2020',
keepNames: true,
minify: true,
legalComments: 'external'
})
]
},
externals: function({ request }, callback) {
const isExternal = packageExternals.some(
moduleName => request && new RegExp(`^${moduleName}(/|$)`, 'i').test(request)
);
if (isExternal){
// @ts-ignore
return callback(undefined, `commonjs ${request}`);
}
// @ts-ignore
callback();
},
plugins: [
new WatchMarkersPlugin(),
new webpack.IgnorePlugin({
resourceRegExp: /^canvas$/,
contextRegExp: /jsdom$/,
}),
new webpack.DefinePlugin({
__webpack_build_info__: JSON.stringify({
version: packageJson.version,
description: packageJson.description,
buildDate: new Date().toISOString()
__webpack_build_info__: JSON.stringify({
version: packageJson.version,
description: packageJson.description,
buildDate: new Date().toISOString()
})
})
]
],
infrastructureLogging: {
level: "log"
}
};

export default common;
2 changes: 1 addition & 1 deletion packages/core/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ module.exports = {
'!**/node_modules/**'
],
transform: {
'^.+\\.ts$': ['ts-jest', { isolatedModules: true }]
'^.+\\.ts$': ['ts-jest', { isolatedModules: true, esModuleInterop: true }]
}
};
2 changes: 1 addition & 1 deletion packages/core/src/fs/nodeFileSystem.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fs from 'fs';
import * as path from 'path';
import * as globby from 'globby';
import globby from 'globby';
import { injectable, LifecyclePolicy } from '../index';
import { FileInfo, FileStat, FileSystem, StatsOptions, WriteOptions } from './fileSystem';

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/logging/writers/fancyConsoleWriter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LogWriter, LogEntry, LogLevel } from '..';
import * as chalk from 'chalk';
import chalk from 'chalk';
import { DateTime } from 'luxon';

export class FancyConsoleWriterOptions {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/logging/writers/terminalWriter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as vscode from 'vscode';
import * as chalk from 'chalk';
import chalk from 'chalk';
import { DateTime } from 'luxon';
import { LogLevel, LogWriter, LogEntry } from '../../logging';

Expand Down
2 changes: 1 addition & 1 deletion packages/omniscript/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ module.exports = {
],
testRegex: "(\\.)(test)\\.[jt]sx?$",
transform: {
'^.+\\.ts$': ['ts-jest', { isolatedModules: true }]
'^.+\\.ts$': ['ts-jest', { isolatedModules: true, esModuleInterop: true }]
}
};
2 changes: 1 addition & 1 deletion packages/salesforce/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ module.exports = {
'!**/node_modules/**'
],
transform: {
'^.+\\.ts$': ['ts-jest', { isolatedModules: true }]
'^.+\\.ts$': ['ts-jest', { isolatedModules: true, esModuleInterop: true }]
}
};
2 changes: 1 addition & 1 deletion packages/salesforce/src/deploy/retrieveResultPackage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import * as path from 'path';
import * as fs from 'fs-extra';
import * as ZipArchive from 'jszip';
import ZipArchive from 'jszip';
import { directoryName, fileName as baseName , groupBy } from '@vlocode/util';
import { FileProperties, RetrieveResult } from '../connection';
import { SalesforcePackageComponent, SalesforcePackageComponentFile } from '../deploymentPackage';
Expand Down
2 changes: 1 addition & 1 deletion packages/salesforce/src/deploymentPackage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import * as path from 'path';
import * as ZipArchive from 'jszip';
import ZipArchive from 'jszip';
import { Iterable, XML , directoryName, arrayMapPush, asArray, groupBy, stringEqualsIgnoreCase } from '@vlocode/util';
import { FileSystem } from '@vlocode/core';
import { PackageManifest } from './deploy/packageXml';
Expand Down
4 changes: 2 additions & 2 deletions packages/salesforce/src/deploymentPackageBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path';
import * as chalk from 'chalk';
import * as ZipArchive from 'jszip';
import chalk from 'chalk';
import ZipArchive from 'jszip';

import { Logger, injectable , LifecyclePolicy, CachedFileSystemAdapter , FileSystem, Container } from '@vlocode/core';
import { cache, substringAfterLast , Iterable, XML, CancellationToken, FileSystemUri } from '@vlocode/util';
Expand Down
4 changes: 2 additions & 2 deletions packages/salesforce/src/metadataRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as registryData from './registry/metadataRegistry.json';
import registryData from './registry/metadataRegistry.json';
import { MetadataType as RegistryMetadataType } from './registry/types';
import { singletonMixin } from '@vlocode/util';
import { injectable, LifecyclePolicy, Logger } from '@vlocode/core';
import * as urlFormats from './metadataUrls.json';
import urlFormats from './metadataUrls.json';

export interface MetadataUrlFormat {
query: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/salesforce/src/queryParser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { container } from "@vlocode/core";
import { lazy } from "@vlocode/util";
import * as assert from "assert";
import assert from "assert";
import { NamespaceService } from './namespaceService';

export type QueryUnary = { left?: undefined, operator: string, right: QueryBinary | QueryUnary | string };
Expand Down
2 changes: 1 addition & 1 deletion packages/salesforce/src/salesforceDeployService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Stream } from 'stream';
import * as ZipArchive from 'jszip';
import ZipArchive from 'jszip';

import { Logger, injectable } from '@vlocode/core';
import { Timer, removeAll, stringEqualsIgnoreCase, Iterable } from '@vlocode/util';
Expand Down
4 changes: 2 additions & 2 deletions packages/salesforce/src/types/jsforce.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Re-export types from JSForce which are directly exposed by this module
// with this we can avoid other modules from depending on JSForce as well making
// a more clear dependency graph within Vlocode
export { Connection, DescribeSObjectResult, DescribeGlobalSObjectResult, DescribeGlobalResult,
export type { Connection, DescribeSObjectResult, DescribeGlobalSObjectResult, DescribeGlobalResult,
DescribeSObjectOptions, BatchDescribeSObjectOptions, Field, ExtraTypeInfo, ScopeInfo, SOAPType } from 'jsforce';

// Other meta-types from JSForce
export { FilteredLookupInfo, RecordTypeInfo, ChildRelationship, NamedLayoutInfo, FieldType } from 'jsforce';
export type { FilteredLookupInfo, RecordTypeInfo, ChildRelationship, NamedLayoutInfo, FieldType } from 'jsforce';
24 changes: 17 additions & 7 deletions packages/util/src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,14 +453,24 @@ export function except<T>(source: ReadonlyArray<T>, target: ReadonlyArray<T>): A
}

/**
* Segregate an Array into a true-ish and false-ish Array. The first element of the result will contain the all elements where the filter returns a
* true-ish value the second element of the result of the result will contain all items for which the filter returned a false-ish value
* @param array Array
*/
export function segregate<T>(array: Array<T>, filter: (item: T) => any) : [ Array<T>, Array<T> ] {
* Segregate the elements of the source array into two distinct arrays the first array holding the values for which the predicate returned true
* and the second array holding the values for which the predicate returned false.
* @param array Array to segregate
* @param predicate Predicate to segregate the array
* @returns A tuple with two arrays the first array holding the values for which the predicate returned true and the second array
* holding the values for which the predicate returned false.
* @example
* ```typescript
* // Segregate even and odd numbers
* const [ even, odd ] = segregate([ 1, 2, 3, 4, 5 ], i => i % 2 == 0);
* console.log(even); // [ 2, 4 ]
* console.log(odd); // [ 1, 3, 5 ]
* ```
*/
export function segregate<T>(array: Array<T>, predicate: (item: T, index: number) => any) : [ Array<T>, Array<T> ] {
const result: [ Array<T>, Array<T> ] = [ new Array<T>(), new Array<T>() ];
array.forEach(item => {
result[filter(item) ? 0 : 1].push(item)
array.forEach((item, index) => {
result[predicate(item, index) ? 0 : 1].push(item)
});
return result;
}
Expand Down
Loading

0 comments on commit 692de00

Please sign in to comment.