Skip to content

Commit de08216

Browse files
authored
Lazy load some more npm dependencies and smarter imports for lodash (microsoft#3461)
For microsoft#3018
1 parent dbabe30 commit de08216

File tree

20 files changed

+132
-63
lines changed

20 files changed

+132
-63
lines changed

build/webpack/common.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,17 @@ exports.nodeModulesToExternalize = [
1414
'unicode/category/Mn',
1515
'unicode/category/Mc',
1616
'unicode/category/Nd',
17-
'unicode/category/Pc'
17+
'unicode/category/Pc',
18+
'@jupyterlab/services',
19+
'azure-storage',
20+
'request',
21+
'request-progress',
22+
'source-map',
23+
'file-matcher',
24+
'diff-match-patch',
25+
'sudo-prompt',
26+
'node-stream-zip',
27+
'xml2js'
1828
];
1929
function getDefaultPlugins(name) {
2030
const plugins = [];

build/webpack/common.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// Copyright (c) Microsoft Corporation. All rights reserved.
32
// Licensed under the MIT License.
43

@@ -16,7 +15,17 @@ export const nodeModulesToExternalize = [
1615
'unicode/category/Mn',
1716
'unicode/category/Mc',
1817
'unicode/category/Nd',
19-
'unicode/category/Pc'
18+
'unicode/category/Pc',
19+
'@jupyterlab/services',
20+
'azure-storage',
21+
'request',
22+
'request-progress',
23+
'source-map',
24+
'file-matcher',
25+
'diff-match-patch',
26+
'sudo-prompt',
27+
'node-stream-zip',
28+
'xml2js'
2029
];
2130

2231
export function getDefaultPlugins(name: 'extension' | 'debugger' | 'dependencies' | 'datascience-ui') {

build/webpack/webpack.extension.dependencies.config.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ const config = {
1717
node: {
1818
__dirname: false
1919
},
20+
module: {
21+
rules: [
22+
{
23+
// JupyterServices imports node-fetch using `eval`.
24+
test: /@jupyterlab[\\\/]services[\\\/].*js$/,
25+
use: [
26+
{
27+
loader: path.join(__dirname, 'loaders', 'fixEvalRequire.js')
28+
}
29+
]
30+
}
31+
]
32+
},
2033
externals: [
2134
'vscode',
2235
'commonjs'

build/webpack/webpack.extension.dependencies.config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ const config: webpack.Configuration = {
2121
node: {
2222
__dirname: false
2323
},
24+
module: {
25+
rules: [
26+
{
27+
// JupyterServices imports node-fetch using `eval`.
28+
test: /@jupyterlab[\\\/]services[\\\/].*js$/,
29+
use: [
30+
{
31+
loader: path.join(__dirname, 'loaders', 'fixEvalRequire.js')
32+
}
33+
]
34+
}
35+
]
36+
},
2437
externals: [
2538
'vscode',
2639
'commonjs'

src/client/activation/downloader.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
'use strict';
55

66
import * as path from 'path';
7-
import * as requestProgress from 'request-progress';
87
import { ProgressLocation, window } from 'vscode';
98
import { STANDARD_OUTPUT_CHANNEL } from '../common/constants';
109
import { IFileSystem } from '../common/platform/types';
@@ -20,8 +19,6 @@ import {
2019
import { PlatformData } from './platformData';
2120
import { IHttpClient, ILanguageServerDownloader, ILanguageServerFolderService } from './types';
2221

23-
// tslint:disable-next-line:no-require-imports no-var-requires
24-
const StreamZip = require('node-stream-zip');
2522
const downloadFileExtension = '.nupkg';
2623

2724
export class LanguageServerDownloader implements ILanguageServerDownloader {
@@ -98,9 +95,11 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
9895

9996
await window.withProgress({
10097
location: ProgressLocation.Window
101-
}, (progress) => {
98+
}, async (progress) => {
10299
const httpClient = this.serviceContainer.get<IHttpClient>(IHttpClient);
103-
requestProgress(httpClient.downloadFile(uri))
100+
const req = await httpClient.downloadFile(uri);
101+
const requestProgress = await import('request-progress');
102+
requestProgress(req)
104103
.on('progress', (state) => {
105104
// https://www.npmjs.com/package/request-progress
106105
const received = Math.round(state.size.transferred / 1024);
@@ -134,6 +133,8 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
134133
await window.withProgress({
135134
location: ProgressLocation.Window
136135
}, (progress) => {
136+
// tslint:disable-next-line:no-require-imports no-var-requires
137+
const StreamZip = require('node-stream-zip');
137138
const zip = new StreamZip({
138139
file: tempFilePath,
139140
storeEntries: true

src/client/activation/languageServer/languageServer.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator {
151151
const settings = this.configuration.getSettings();
152152
if (!settings.downloadLanguageServer) {
153153
// Depends on .NET Runtime or SDK. Typically development-only case.
154-
this.languageClient = this.createSimpleLanguageClient(clientOptions);
154+
this.languageClient = await this.createSimpleLanguageClient(clientOptions);
155155
await this.startLanguageClient();
156156
return true;
157157
}
@@ -163,7 +163,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator {
163163
}
164164

165165
const serverModule = path.join(this.context.extensionPath, this.languageServerFolder, this.platformData.getEngineExecutableName());
166-
this.languageClient = this.createSelfContainedLanguageClient(serverModule, clientOptions);
166+
this.languageClient = await this.createSelfContainedLanguageClient(serverModule, clientOptions);
167167
try {
168168
await this.startLanguageClient();
169169
this.languageClient.onTelemetry(telemetryEvent => {
@@ -197,23 +197,25 @@ export class LanguageServerExtensionActivator implements IExtensionActivator {
197197
this.startupCompleted.resolve();
198198
}
199199

200-
private createSimpleLanguageClient(clientOptions: LanguageClientOptions): LanguageClient {
200+
private async createSimpleLanguageClient(clientOptions: LanguageClientOptions): Promise<LanguageClient> {
201201
const commandOptions = { stdio: 'pipe' };
202202
const serverModule = path.join(this.context.extensionPath, this.languageServerFolder, this.platformData.getEngineDllName());
203203
const serverOptions: ServerOptions = {
204204
run: { command: dotNetCommand, args: [serverModule], options: commandOptions },
205205
debug: { command: dotNetCommand, args: [serverModule, '--debug'], options: commandOptions }
206206
};
207-
return new LanguageClient(PYTHON, languageClientName, serverOptions, clientOptions);
207+
const vscodeLanaguageClient = await import('vscode-languageclient');
208+
return new vscodeLanaguageClient.LanguageClient(PYTHON, languageClientName, serverOptions, clientOptions);
208209
}
209210

210-
private createSelfContainedLanguageClient(serverModule: string, clientOptions: LanguageClientOptions): LanguageClient {
211+
private async createSelfContainedLanguageClient(serverModule: string, clientOptions: LanguageClientOptions): Promise<LanguageClient> {
211212
const options = { stdio: 'pipe' };
212213
const serverOptions: ServerOptions = {
213214
run: { command: serverModule, rgs: [], options: options },
214215
debug: { command: serverModule, args: ['--debug'], options }
215216
};
216-
return new LanguageClient(PYTHON, languageClientName, serverOptions, clientOptions);
217+
const vscodeLanaguageClient = await import('vscode-languageclient');
218+
return new vscodeLanaguageClient.LanguageClient(PYTHON, languageClientName, serverOptions, clientOptions);
217219
}
218220

219221
// tslint:disable-next-line:member-ordering

src/client/activation/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export interface IExtensionActivator {
2626

2727
export const IHttpClient = Symbol('IHttpClient');
2828
export interface IHttpClient {
29-
downloadFile(uri: string): RequestResult;
29+
downloadFile(uri: string): Promise<RequestResult>;
3030
getJSON<T>(uri: string): Promise<T>;
3131
}
3232

src/client/common/editor.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as dmp from 'diff-match-patch';
1+
import { Diff, diff_match_patch } from 'diff-match-patch';
22
import * as fs from 'fs-extra';
33
import { injectable } from 'inversify';
44
import * as md5 from 'md5';
@@ -17,7 +17,7 @@ enum EditAction {
1717
const NEW_LINE_LENGTH = EOL.length;
1818

1919
class Patch {
20-
public diffs!: dmp.Diff[];
20+
public diffs!: Diff[];
2121
public start1!: number;
2222
public start2!: number;
2323
public length1!: number;
@@ -61,7 +61,8 @@ export function getTextEditsFromPatch(before: string, patch: string): TextEdit[]
6161
// Remove the text added by unified_diff
6262
// # Work around missing newline (http://bugs.python.org/issue2142).
6363
patch = patch.replace(/\\ No newline at end of file[\r\n]/, '');
64-
64+
// tslint:disable-next-line:no-require-imports
65+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
6566
const d = new dmp.diff_match_patch();
6667
const patches = patch_fromText.call(d, patch);
6768
if (!Array.isArray(patches) || patches.length === 0) {
@@ -114,6 +115,8 @@ export function getWorkspaceEditsFromPatch(filePatches: string[], workspaceRoot?
114115
// # Work around missing newline (http://bugs.python.org/issue2142).
115116
patch = patch.replace(/\\ No newline at end of file[\r\n]/, '');
116117

118+
// tslint:disable-next-line:no-require-imports
119+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
117120
const d = new dmp.diff_match_patch();
118121
const patches = patch_fromText.call(d, patch);
119122
if (!Array.isArray(patches) || patches.length === 0) {
@@ -150,6 +153,8 @@ export function getWorkspaceEditsFromPatch(filePatches: string[], workspaceRoot?
150153
return workspaceEdit;
151154
}
152155
export function getTextEdits(before: string, after: string): TextEdit[] {
156+
// tslint:disable-next-line:no-require-imports
157+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
153158
const d = new dmp.diff_match_patch();
154159
const diffs = d.diff_main(before, after);
155160
return getTextEditsInternal(before, diffs).map(edit => edit.apply());
@@ -178,6 +183,8 @@ function getTextEditsInternal(before: string, diffs: [number, string][], startLi
178183
}
179184
}
180185

186+
// tslint:disable-next-line:no-require-imports
187+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
181188
// tslint:disable-next-line:switch-default
182189
switch (diffs[i][0]) {
183190
case dmp.DIFF_DELETE:
@@ -261,7 +268,7 @@ function patch_fromText(textline): Patch[] {
261268
throw new Error(`Invalid patch string: ${text[textPointer]}`);
262269
}
263270
// tslint:disable-next-line:no-any
264-
const patch = new (<any>dmp.diff_match_patch).patch_obj();
271+
const patch = new (<any>diff_match_patch).patch_obj();
265272
patches.push(patch);
266273
patch.start1 = parseInt(m[1], 10);
267274
if (m[2] === '') {
@@ -285,6 +292,8 @@ function patch_fromText(textline): Patch[] {
285292
patch.length2 = parseInt(m[4], 10);
286293
}
287294
textPointer += 1;
295+
// tslint:disable-next-line:no-require-imports
296+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
288297

289298
while (textPointer < text.length) {
290299
const sign = text[textPointer].charAt(0);
@@ -339,6 +348,8 @@ export class EditorUtils implements IEditorUtils {
339348
// # Work around missing newline (http://bugs.python.org/issue2142).
340349
patch = patch.replace(/\\ No newline at end of file[\r\n]/, '');
341350

351+
// tslint:disable-next-line:no-require-imports
352+
const dmp = require('diff-match-patch') as typeof import('diff-match-patch');
342353
const d = new dmp.diff_match_patch();
343354
const patches = patch_fromText.call(d, patch);
344355
if (!Array.isArray(patches) || patches.length === 0) {

src/client/common/installer/moduleInstaller.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
// tslint:disable-next-line:no-require-imports no-var-requires
5-
const sudo = require('sudo-prompt');
6-
74
import * as fs from 'fs';
85
import { injectable } from 'inversify';
96
import * as path from 'path';
@@ -90,6 +87,8 @@ export abstract class ModuleInstaller {
9087

9188
outputChannel.appendLine('');
9289
outputChannel.appendLine(`[Elevated] ${command}`);
90+
// tslint:disable-next-line:no-require-imports no-var-requires
91+
const sudo = require('sudo-prompt');
9392

9493
sudo.exec(command, options, (error, stdout, stderr) => {
9594
if (error) {

src/client/common/net/httpClient.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,27 @@
44
'use strict';
55

66
import { inject, injectable } from 'inversify';
7-
import * as request from 'request';
7+
import * as requestTypes from 'request';
88
import { IHttpClient } from '../../activation/types';
99
import { IServiceContainer } from '../../ioc/types';
1010
import { IWorkspaceService } from '../application/types';
1111

1212
@injectable()
1313
export class HttpClient implements IHttpClient {
14-
public readonly requestOptions: request.CoreOptions;
14+
public readonly requestOptions: requestTypes.CoreOptions;
1515
constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) {
1616
const workspaceService = serviceContainer.get<IWorkspaceService>(IWorkspaceService);
1717
this.requestOptions = { proxy: workspaceService.getConfiguration('http').get('proxy', '') };
1818
}
1919

20-
public downloadFile(uri: string): request.Request {
20+
public async downloadFile(uri: string): Promise<requestTypes.Request> {
21+
// tslint:disable-next-line:no-any
22+
const request = await import('request') as any as typeof requestTypes;
2123
return request(uri, this.requestOptions);
2224
}
23-
public getJSON<T>(uri: string): Promise<T> {
25+
public async getJSON<T>(uri: string): Promise<T> {
26+
// tslint:disable-next-line:no-require-imports
27+
const request = require('request') as typeof requestTypes;
2428
return new Promise<T>((resolve, reject) => {
2529
request(uri, this.requestOptions, (ex, response, body) => {
2630
if (ex) {

0 commit comments

Comments
 (0)