mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:31:43 +00:00
vscode: add experimental esbuild support (#34010)
Co-authored-by: Beatrix <68532117+abeatrix@users.noreply.github.com>
This commit is contained in:
parent
c15f33c565
commit
bf6fadfed9
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@ -33,6 +33,7 @@
|
||||
"--extensionDevelopmentKind=web",
|
||||
"--disable-web-security",
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/client/vscode/dist/webworker/*.js"],
|
||||
},
|
||||
{
|
||||
|
||||
@ -4,7 +4,9 @@ import * as esbuild from 'esbuild'
|
||||
import { EditorFeature, featuresArr } from 'monaco-editor-webpack-plugin/out/features'
|
||||
import { EditorLanguage, languagesArr } from 'monaco-editor-webpack-plugin/out/languages'
|
||||
|
||||
import { MONACO_LANGUAGES_AND_FEATURES, ROOT_PATH } from '@sourcegraph/build-config'
|
||||
import { MONACO_LANGUAGES_AND_FEATURES } from '@sourcegraph/build-config'
|
||||
|
||||
import { ROOT_PATH } from '../paths'
|
||||
|
||||
const monacoModulePath = (modulePath: string): string =>
|
||||
require.resolve(path.join('monaco-editor/esm', modulePath), {
|
||||
@ -57,3 +59,20 @@ export const monacoPlugin = ({
|
||||
build.onLoad({ filter }, () => ({ contents: '', loader: 'js' }))
|
||||
},
|
||||
})
|
||||
|
||||
// TODO(sqs): These Monaco Web Workers could be built as part of the main build if we switch to
|
||||
// using MonacoEnvironment#getWorker (from #getWorkerUrl), which would then let us use the worker
|
||||
// plugin (and in Webpack the worker-loader) to load these instead of needing to hardcode them as
|
||||
// build entrypoints.
|
||||
export const buildMonaco = async (outdir: string): Promise<void> => {
|
||||
await esbuild.build({
|
||||
entryPoints: {
|
||||
'scripts/editor.worker.bundle': 'monaco-editor/esm/vs/editor/editor.worker.js',
|
||||
'scripts/json.worker.bundle': 'monaco-editor/esm/vs/language/json/json.worker.js',
|
||||
},
|
||||
format: 'iife',
|
||||
target: 'es2021',
|
||||
bundle: true,
|
||||
outdir,
|
||||
})
|
||||
}
|
||||
55
client/build-config/src/esbuild/packageResolutionPlugin.ts
Normal file
55
client/build-config/src/esbuild/packageResolutionPlugin.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { CachedInputFileSystem, ResolverFactory } from 'enhanced-resolve'
|
||||
import * as esbuild from 'esbuild'
|
||||
|
||||
import { NODE_MODULES_PATH } from '../paths'
|
||||
|
||||
interface Resolutions {
|
||||
[fromModule: string]: string
|
||||
}
|
||||
|
||||
/**
|
||||
* An esbuild plugin to redirect imports from one package to another (for example, from 'path' to
|
||||
* 'path-browserify' to run in the browser).
|
||||
*/
|
||||
export const packageResolutionPlugin = (resolutions: Resolutions): esbuild.Plugin => ({
|
||||
name: 'packageResolution',
|
||||
setup: build => {
|
||||
const filter = new RegExp(`^(${Object.keys(resolutions).join('|')})$`)
|
||||
|
||||
const resolver = ResolverFactory.createResolver({
|
||||
fileSystem: new CachedInputFileSystem(fs, 4000),
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
|
||||
symlinks: true, // Resolve workspace symlinks
|
||||
modules: [NODE_MODULES_PATH],
|
||||
})
|
||||
|
||||
build.onResolve({ filter, namespace: 'file' }, async args => {
|
||||
if ((args.kind === 'import-statement' || args.kind === 'require-call') && resolutions[args.path]) {
|
||||
const resolvedPath = await new Promise<string>((resolve, reject) => {
|
||||
resolver.resolve({}, args.resolveDir, resolutions[args.path], {}, (error, filepath) => {
|
||||
if (filepath) {
|
||||
resolve(filepath)
|
||||
} else {
|
||||
reject(error ?? new Error(`Could not resolve file path for ${resolutions[args.path]}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
return { path: resolvedPath }
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const RXJS_RESOLUTIONS: Resolutions = {
|
||||
// Needed because imports of rxjs/internal/... actually import a different variant of
|
||||
// rxjs in the same package, which leads to observables from combineLatestOrDefault (and
|
||||
// other places that use rxjs/internal/...) not being cross-compatible. See
|
||||
// https://stackoverflow.com/questions/53758889/rxjs-subscribeto-js-observable-check-works-in-chrome-but-fails-in-chrome-incogn.
|
||||
'rxjs/internal/OuterSubscriber': require.resolve('rxjs/_esm5/internal/OuterSubscriber'),
|
||||
'rxjs/internal/util/subscribeToResult': require.resolve('rxjs/_esm5/internal/util/subscribeToResult'),
|
||||
'rxjs/internal/util/subscribeToArray': require.resolve('rxjs/_esm5/internal/util/subscribeToArray'),
|
||||
'rxjs/internal/Observable': require.resolve('rxjs/_esm5/internal/Observable'),
|
||||
}
|
||||
27
client/build-config/src/esbuild/plugins.ts
Normal file
27
client/build-config/src/esbuild/plugins.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import * as esbuild from 'esbuild'
|
||||
import signale from 'signale'
|
||||
|
||||
export * from './monacoPlugin'
|
||||
export * from './packageResolutionPlugin'
|
||||
export * from './stylePlugin'
|
||||
export * from './workerPlugin'
|
||||
|
||||
export const buildTimerPlugin: esbuild.Plugin = {
|
||||
name: 'buildTimer',
|
||||
setup: (build: esbuild.PluginBuild): void => {
|
||||
let buildStarted: number
|
||||
build.onStart(() => {
|
||||
buildStarted = Date.now()
|
||||
})
|
||||
build.onEnd(() => console.log(`# esbuild: build took ${Date.now() - buildStarted}ms`))
|
||||
},
|
||||
}
|
||||
|
||||
export const experimentalNoticePlugin: esbuild.Plugin = {
|
||||
name: 'experimentalNotice',
|
||||
setup: (): void => {
|
||||
signale.info(
|
||||
'esbuild usage is experimental. See https://docs.sourcegraph.com/dev/background-information/web/build#esbuild.'
|
||||
)
|
||||
},
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import { ResolverFactory, CachedInputFileSystem } from 'enhanced-resolve'
|
||||
import esbuild from 'esbuild'
|
||||
import postcss from 'postcss'
|
||||
import postcssModules from 'postcss-modules'
|
||||
import sass from 'sass'
|
||||
|
||||
import { ROOT_PATH } from '@sourcegraph/build-config'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
import postcssConfig from '../../../../postcss.config'
|
||||
import { NODE_MODULES_PATH, ROOT_PATH } from '../paths'
|
||||
|
||||
/**
|
||||
* An esbuild plugin that builds .css and .scss stylesheets (including support for CSS modules).
|
||||
@ -98,14 +98,29 @@ export const stylePlugin: esbuild.Plugin = {
|
||||
return output
|
||||
}
|
||||
|
||||
const resolver = ResolverFactory.createResolver({
|
||||
fileSystem: new CachedInputFileSystem(fs, 4000),
|
||||
extensions: ['.css', '.scss'],
|
||||
symlinks: true, // Resolve workspace symlinks
|
||||
modules: [NODE_MODULES_PATH],
|
||||
})
|
||||
|
||||
build.onResolve({ filter: /\.s?css$/, namespace: 'file' }, async args => {
|
||||
const inputPath = path.join(args.resolveDir, args.path)
|
||||
const inputPath = await new Promise<string>((resolve, reject) => {
|
||||
resolver.resolve({}, args.resolveDir, args.path, {}, (error, filepath) => {
|
||||
if (filepath) {
|
||||
resolve(filepath)
|
||||
} else {
|
||||
reject(error ?? new Error(`Could not resolve file path for ${args.path}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const { outputPath, outputContents, includedFiles } = await cachedTransform({
|
||||
inputPath,
|
||||
inputContents: await fs.promises.readFile(inputPath, 'utf8'),
|
||||
})
|
||||
const isCSSModule = outputPath.endsWith('.module.css')
|
||||
|
||||
return {
|
||||
path: outputPath,
|
||||
namespace: isCSSModule ? 'css-module' : 'css',
|
||||
@ -2,7 +2,7 @@ import path from 'path'
|
||||
|
||||
import * as esbuild from 'esbuild'
|
||||
|
||||
import { BUILD_OPTIONS } from './build'
|
||||
import { packageResolutionPlugin, RXJS_RESOLUTIONS } from '@sourcegraph/build-config'
|
||||
|
||||
async function buildWorker(
|
||||
workerPath: string,
|
||||
@ -12,7 +12,12 @@ async function buildWorker(
|
||||
entryPoints: [workerPath],
|
||||
bundle: true,
|
||||
write: false,
|
||||
plugins: BUILD_OPTIONS.plugins?.filter(plugin => plugin.name === 'packageResolution'),
|
||||
plugins: [
|
||||
packageResolutionPlugin({
|
||||
path: require.resolve('path-browserify'),
|
||||
...RXJS_RESOLUTIONS,
|
||||
}),
|
||||
],
|
||||
sourcemap: true,
|
||||
metafile: true,
|
||||
...extraConfig,
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './esbuild/plugins'
|
||||
export * from './paths'
|
||||
export * from './webpack/babel-loader'
|
||||
export * from './webpack/css-loader'
|
||||
|
||||
@ -21,6 +21,7 @@ const {
|
||||
watchCSSModulesTypings,
|
||||
} = require('../shared/gulpfile')
|
||||
|
||||
const buildScripts = require('./scripts/build')
|
||||
const createWebpackConfig = require('./webpack.config')
|
||||
|
||||
const WEBPACK_STATS_OPTIONS = {
|
||||
@ -67,6 +68,10 @@ async function watchWebpack() {
|
||||
})
|
||||
}
|
||||
|
||||
async function esbuild() {
|
||||
await buildScripts.build()
|
||||
}
|
||||
|
||||
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
|
||||
const generate = gulp.parallel(schema, graphQlSchema, graphQlOperations, cssModulesTypings)
|
||||
|
||||
@ -88,4 +93,4 @@ const watch = gulp.series(
|
||||
gulp.parallel(watchGenerators, watchWebpack)
|
||||
)
|
||||
|
||||
module.exports = { build, watch, webpack, watchWebpack }
|
||||
module.exports = { build, watch, webpack, watchWebpack, esbuild }
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"version": "2.2.3",
|
||||
"description": "Sourcegraph for VS Code",
|
||||
"publisher": "sourcegraph",
|
||||
"sideEffects": false,
|
||||
"sideEffects": true,
|
||||
"license": "Apache-2.0",
|
||||
"icon": "images/logo.png",
|
||||
"repository": {
|
||||
@ -221,6 +221,9 @@
|
||||
"test": "ts-node ./tests/runTests.ts",
|
||||
"package": "ts-node ./scripts/package.ts",
|
||||
"task:gulp": "cross-env NODE_OPTIONS=\"--max_old_space_size=8192\" gulp",
|
||||
"build:esbuild": "NODE_ENV=development yarn task:gulp esbuild",
|
||||
"build:esbuild:web": "NODE_ENV=development TARGET_TYPE=webworker yarn task:gulp esbuild",
|
||||
"watch:esbuild": "NODE_ENV=development WATCH=true yarn task:gulp esbuild",
|
||||
"build": "NODE_ENV=production yarn task:gulp webpack",
|
||||
"build:node": "NODE_ENV=production TARGET_TYPE=node yarn task:gulp webpack",
|
||||
"build:web": "NODE_ENV=production TARGET_TYPE=webworker yarn task:gulp webpack",
|
||||
|
||||
5
client/vscode/scripts/buffer-shim.js
Normal file
5
client/vscode/scripts/buffer-shim.js
Normal file
@ -0,0 +1,5 @@
|
||||
// This file is used for esbuild's `inject` option
|
||||
// in order to load node polyfills in the webworker
|
||||
// extension host.
|
||||
// See: https://esbuild.github.io/api/#inject.
|
||||
export const Buffer = require('buffer/').Buffer
|
||||
149
client/vscode/scripts/build.ts
Normal file
149
client/vscode/scripts/build.ts
Normal file
@ -0,0 +1,149 @@
|
||||
import { existsSync } from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import * as esbuild from 'esbuild'
|
||||
import { rm } from 'shelljs'
|
||||
|
||||
import {
|
||||
buildMonaco,
|
||||
monacoPlugin,
|
||||
MONACO_LANGUAGES_AND_FEATURES,
|
||||
packageResolutionPlugin,
|
||||
stylePlugin,
|
||||
workerPlugin,
|
||||
RXJS_RESOLUTIONS,
|
||||
buildTimerPlugin,
|
||||
} from '@sourcegraph/build-config'
|
||||
|
||||
const watch = !!process.env.WATCH
|
||||
const minify = process.env.NODE_ENV === 'production'
|
||||
const outdir = path.join(__dirname, '../dist')
|
||||
const isTest = !!process.env.IS_TEST
|
||||
|
||||
const TARGET_TYPE = process.env.TARGET_TYPE
|
||||
|
||||
const SHARED_CONFIG = {
|
||||
outdir,
|
||||
watch,
|
||||
minify,
|
||||
sourcemap: true,
|
||||
}
|
||||
|
||||
export async function build(): Promise<void> {
|
||||
if (existsSync(outdir)) {
|
||||
rm('-rf', outdir)
|
||||
}
|
||||
|
||||
const buildPromises = []
|
||||
|
||||
if (TARGET_TYPE === 'node' || !TARGET_TYPE) {
|
||||
buildPromises.push(
|
||||
esbuild.build({
|
||||
entryPoints: { extension: path.join(__dirname, '/../src/extension.ts') },
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
platform: 'node',
|
||||
external: ['vscode'],
|
||||
banner: { js: 'global.Buffer = require("buffer").Buffer' },
|
||||
define: {
|
||||
'process.env.IS_TEST': isTest ? 'true' : 'false',
|
||||
},
|
||||
...SHARED_CONFIG,
|
||||
outdir: path.join(SHARED_CONFIG.outdir, 'node'),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (TARGET_TYPE === 'webworker' || !TARGET_TYPE) {
|
||||
buildPromises.push(
|
||||
esbuild.build({
|
||||
entryPoints: { extension: path.join(__dirname, '/../src/extension.ts') },
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
platform: 'browser',
|
||||
external: ['vscode'],
|
||||
define: {
|
||||
'process.env.IS_TEST': isTest ? 'true' : 'false',
|
||||
global: 'globalThis',
|
||||
},
|
||||
inject: ['./scripts/process-shim.js', './scripts/buffer-shim.js'],
|
||||
plugins: [
|
||||
packageResolutionPlugin({
|
||||
process: require.resolve('process/browser'),
|
||||
path: require.resolve('path-browserify'),
|
||||
http: require.resolve('stream-http'),
|
||||
https: require.resolve('https-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
util: require.resolve('util'),
|
||||
events: require.resolve('events'),
|
||||
buffer: require.resolve('buffer/'),
|
||||
'./browserActionsNode': path.resolve(__dirname, '../src', 'link-commands', 'browserActionsWeb'),
|
||||
}),
|
||||
],
|
||||
...SHARED_CONFIG,
|
||||
outdir: path.join(SHARED_CONFIG.outdir, 'webworker'),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
buildPromises.push(
|
||||
esbuild.build({
|
||||
entryPoints: {
|
||||
helpSidebar: path.join(__dirname, '../src/webview/sidebars/help'),
|
||||
searchSidebar: path.join(__dirname, '../src/webview/sidebars/search'),
|
||||
searchPanel: path.join(__dirname, '../src/webview/search-panel'),
|
||||
style: path.join(__dirname, '../src/webview/index.scss'),
|
||||
},
|
||||
bundle: true,
|
||||
format: 'esm',
|
||||
platform: 'browser',
|
||||
splitting: true,
|
||||
plugins: [
|
||||
stylePlugin,
|
||||
workerPlugin,
|
||||
packageResolutionPlugin({
|
||||
path: require.resolve('path-browserify'),
|
||||
...RXJS_RESOLUTIONS,
|
||||
'./Link': require.resolve('../src/webview/search-panel/alias/Link'),
|
||||
'../Link': require.resolve('../src/webview/search-panel/alias/Link'),
|
||||
'./RepoSearchResult': require.resolve('../src/webview/search-panel/alias/RepoSearchResult'),
|
||||
'./CommitSearchResult': require.resolve('../src/webview/search-panel/alias/CommitSearchResult'),
|
||||
'./FileMatchChildren': require.resolve('../src/webview/search-panel/alias/FileMatchChildren'),
|
||||
'./RepoFileLink': require.resolve('../src/webview/search-panel/alias/RepoFileLink'),
|
||||
'../documentation/ModalVideo': require.resolve('../src/webview/search-panel/alias/ModalVideo'),
|
||||
}),
|
||||
// Note: leads to "file has no exports" warnings
|
||||
monacoPlugin(MONACO_LANGUAGES_AND_FEATURES),
|
||||
buildTimerPlugin,
|
||||
{
|
||||
name: 'codiconsDeduplicator',
|
||||
setup(build): void {
|
||||
build.onLoad({ filter: /\.ttf$/ }, args => {
|
||||
// Both `@vscode/codicons` and `monaco-editor`
|
||||
// node modules include a `codicons.ttf` file,
|
||||
// so null one out.
|
||||
if (!args.path.includes('@vscode/codicons')) {
|
||||
return {
|
||||
contents: '',
|
||||
loader: 'text',
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
loader: {
|
||||
'.ttf': 'file',
|
||||
},
|
||||
assetNames: '[name]',
|
||||
ignoreAnnotations: true,
|
||||
treeShaking: false,
|
||||
...SHARED_CONFIG,
|
||||
outdir: path.join(SHARED_CONFIG.outdir, 'webview'),
|
||||
})
|
||||
)
|
||||
|
||||
buildPromises.push(buildMonaco(outdir))
|
||||
|
||||
await Promise.all(buildPromises)
|
||||
}
|
||||
5
client/vscode/scripts/process-shim.js
Normal file
5
client/vscode/scripts/process-shim.js
Normal file
@ -0,0 +1,5 @@
|
||||
// This file is used for esbuild's `inject` option
|
||||
// in order to load node polyfills in the webworker
|
||||
// extension host.
|
||||
// See: https://esbuild.github.io/api/#inject.
|
||||
export const process = require('process/browser')
|
||||
@ -1,7 +1,7 @@
|
||||
@import './forkedBranded.scss';
|
||||
@import './theming/highlight.scss';
|
||||
@import './theming/monaco.scss';
|
||||
@import '~@vscode/codicons/dist/codicon.css';
|
||||
@import '../../../../node_modules/@vscode/codicons/dist/codicon.css';
|
||||
|
||||
:root {
|
||||
// v2/debt: redefine our CSS variables using VS Code's CSS variables
|
||||
|
||||
@ -23,15 +23,15 @@ export async function initializeSearchPanelWebview({
|
||||
searchPanelAPI: Comlink.Remote<SearchPanelAPI>
|
||||
webviewPanel: vscode.WebviewPanel
|
||||
}> {
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
const panel = vscode.window.createWebviewPanel('sourcegraphSearch', 'Sourcegraph', vscode.ViewColumn.One, {
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
enableFindWidget: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'dist', 'webview')],
|
||||
localResourceRoots: [webviewPath],
|
||||
})
|
||||
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
const scriptSource = panel.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'searchPanel.js'))
|
||||
const cssModuleSource = panel.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'searchPanel.css'))
|
||||
const styleSource = panel.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'style.css'))
|
||||
@ -53,7 +53,6 @@ export async function initializeSearchPanelWebview({
|
||||
// Expose the "Core" extension API to the Webview.
|
||||
Comlink.expose(extensionCoreAPI, expose)
|
||||
|
||||
// Use a nonce to only allow specific scripts to be run
|
||||
const nonce = getNonce()
|
||||
|
||||
panel.iconPath = vscode.Uri.joinPath(extensionUri, 'images', 'logo.svg')
|
||||
@ -85,7 +84,7 @@ export async function initializeSearchPanelWebview({
|
||||
</head>
|
||||
<body class="search-panel">
|
||||
<div id="root" />
|
||||
<script nonce="${nonce}" src="${scriptSource.toString()}"></script>
|
||||
<script type="module" nonce="${nonce}" src="${scriptSource.toString()}"></script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
@ -107,13 +106,13 @@ export function initializeSearchSidebarWebview({
|
||||
}): {
|
||||
searchSidebarAPI: Comlink.Remote<SearchSidebarAPI>
|
||||
} {
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
webviewView.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'dist', 'webview')],
|
||||
localResourceRoots: [webviewPath],
|
||||
}
|
||||
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
const scriptSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'searchSidebar.js'))
|
||||
const cssModuleSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'searchSidebar.css'))
|
||||
const styleSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'style.css'))
|
||||
@ -151,7 +150,7 @@ export function initializeSearchSidebarWebview({
|
||||
</head>
|
||||
<body class="search-sidebar">
|
||||
<div id="root" />
|
||||
<script src="${scriptSource.toString()}"></script>
|
||||
<script type="module" src="${scriptSource.toString()}"></script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
@ -169,13 +168,13 @@ export function initializeHelpSidebarWebview({
|
||||
}): {
|
||||
helpSidebarAPI: Comlink.Remote<HelpSidebarAPI>
|
||||
} {
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
webviewView.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'dist', 'webview')],
|
||||
localResourceRoots: [webviewPath],
|
||||
}
|
||||
|
||||
const webviewPath = vscode.Uri.joinPath(extensionUri, 'dist', 'webview')
|
||||
|
||||
const scriptSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'helpSidebar.js'))
|
||||
const cssModuleSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'helpSidebar.css'))
|
||||
const styleSource = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'style.css'))
|
||||
@ -202,7 +201,7 @@ export function initializeHelpSidebarWebview({
|
||||
<link rel="stylesheet" href="${cssModuleSource.toString()}" />
|
||||
</head>
|
||||
<div id="root" />
|
||||
<script src="${scriptSource.toString()}"></script>
|
||||
<script type="module" src="${scriptSource.toString()}"></script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
import path from 'path'
|
||||
|
||||
import * as esbuild from 'esbuild'
|
||||
import signale from 'signale'
|
||||
|
||||
import { MONACO_LANGUAGES_AND_FEATURES, ROOT_PATH, STATIC_ASSETS_PATH } from '@sourcegraph/build-config'
|
||||
import {
|
||||
MONACO_LANGUAGES_AND_FEATURES,
|
||||
ROOT_PATH,
|
||||
STATIC_ASSETS_PATH,
|
||||
stylePlugin,
|
||||
packageResolutionPlugin,
|
||||
workerPlugin,
|
||||
monacoPlugin,
|
||||
RXJS_RESOLUTIONS,
|
||||
buildMonaco,
|
||||
experimentalNoticePlugin,
|
||||
buildTimerPlugin,
|
||||
} from '@sourcegraph/build-config'
|
||||
|
||||
import { ENVIRONMENT_CONFIG } from '../utils'
|
||||
|
||||
import { manifestPlugin } from './manifestPlugin'
|
||||
import { monacoPlugin } from './monacoPlugin'
|
||||
import { packageResolutionPlugin } from './packageResolutionPlugin'
|
||||
import { stylePlugin } from './stylePlugin'
|
||||
import { workerPlugin } from './workerPlugin'
|
||||
|
||||
const isEnterpriseBuild = ENVIRONMENT_CONFIG.ENTERPRISE
|
||||
|
||||
@ -35,35 +42,11 @@ export const BUILD_OPTIONS: esbuild.BuildOptions = {
|
||||
manifestPlugin,
|
||||
packageResolutionPlugin({
|
||||
path: require.resolve('path-browserify'),
|
||||
|
||||
// Needed because imports of rxjs/internal/... actually import a different variant of
|
||||
// rxjs in the same package, which leads to observables from combineLatestOrDefault (and
|
||||
// other places that use rxjs/internal/...) not being cross-compatible. See
|
||||
// https://stackoverflow.com/questions/53758889/rxjs-subscribeto-js-observable-check-works-in-chrome-but-fails-in-chrome-incogn.
|
||||
'rxjs/internal/OuterSubscriber': require.resolve('rxjs/_esm5/internal/OuterSubscriber'),
|
||||
'rxjs/internal/util/subscribeToResult': require.resolve('rxjs/_esm5/internal/util/subscribeToResult'),
|
||||
'rxjs/internal/util/subscribeToArray': require.resolve('rxjs/_esm5/internal/util/subscribeToArray'),
|
||||
'rxjs/internal/Observable': require.resolve('rxjs/_esm5/internal/Observable'),
|
||||
...RXJS_RESOLUTIONS,
|
||||
}),
|
||||
monacoPlugin(MONACO_LANGUAGES_AND_FEATURES),
|
||||
{
|
||||
name: 'buildTimer',
|
||||
setup: (build: esbuild.PluginBuild): void => {
|
||||
let buildStarted: number
|
||||
build.onStart(() => {
|
||||
buildStarted = Date.now()
|
||||
})
|
||||
build.onEnd(() => console.log(`# esbuild: build took ${Date.now() - buildStarted}ms`))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'experimentalNotice',
|
||||
setup: (): void => {
|
||||
signale.info(
|
||||
'esbuild usage is experimental. See https://docs.sourcegraph.com/dev/background-information/web/build#esbuild.'
|
||||
)
|
||||
},
|
||||
},
|
||||
buildTimerPlugin,
|
||||
experimentalNoticePlugin,
|
||||
],
|
||||
define: {
|
||||
...Object.fromEntries(
|
||||
@ -90,29 +73,12 @@ export const BUILD_OPTIONS: esbuild.BuildOptions = {
|
||||
treeShaking: false,
|
||||
}
|
||||
|
||||
// TODO(sqs): These Monaco Web Workers could be built as part of the main build if we switch to
|
||||
// using MonacoEnvironment#getWorker (from #getWorkerUrl), which would then let us use the worker
|
||||
// plugin (and in Webpack the worker-loader) to load these instead of needing to hardcode them as
|
||||
// build entrypoints.
|
||||
export const buildMonaco = async (): Promise<void> => {
|
||||
await esbuild.build({
|
||||
entryPoints: {
|
||||
'scripts/editor.worker.bundle': 'monaco-editor/esm/vs/editor/editor.worker.js',
|
||||
'scripts/json.worker.bundle': 'monaco-editor/esm/vs/language/json/json.worker.js',
|
||||
},
|
||||
format: 'iife',
|
||||
target: 'es2021',
|
||||
bundle: true,
|
||||
outdir: STATIC_ASSETS_PATH,
|
||||
})
|
||||
}
|
||||
|
||||
export const build = async (): Promise<void> => {
|
||||
await esbuild.build({
|
||||
...BUILD_OPTIONS,
|
||||
outdir: STATIC_ASSETS_PATH,
|
||||
})
|
||||
await buildMonaco()
|
||||
await buildMonaco(STATIC_ASSETS_PATH)
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import * as esbuild from 'esbuild'
|
||||
|
||||
/**
|
||||
* An esbuild plugin to redirect imports from one package to another (for example, from 'path' to
|
||||
* 'path-browserify' to run in the browser).
|
||||
*/
|
||||
export const packageResolutionPlugin = (resolutions: { [fromModule: string]: string }): esbuild.Plugin => ({
|
||||
name: 'packageResolution',
|
||||
setup: build => {
|
||||
const filter = new RegExp(`^(${Object.keys(resolutions).join('|')})$`)
|
||||
build.onResolve({ filter, namespace: 'file' }, args =>
|
||||
(args.kind === 'import-statement' || args.kind === 'require-call') && resolutions[args.path]
|
||||
? { path: resolutions[args.path] }
|
||||
: undefined
|
||||
)
|
||||
},
|
||||
})
|
||||
@ -5,9 +5,9 @@ import express from 'express'
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware'
|
||||
import signale from 'signale'
|
||||
|
||||
import { STATIC_ASSETS_PATH } from '@sourcegraph/build-config'
|
||||
import { STATIC_ASSETS_PATH, buildMonaco } from '@sourcegraph/build-config'
|
||||
|
||||
import { buildMonaco, BUILD_OPTIONS } from './build'
|
||||
import { BUILD_OPTIONS } from './build'
|
||||
import { assetPathPrefix } from './manifestPlugin'
|
||||
|
||||
export const esbuildDevelopmentServer = async (
|
||||
@ -16,7 +16,7 @@ export const esbuildDevelopmentServer = async (
|
||||
): Promise<void> => {
|
||||
// One-time build (these files only change when the monaco-editor npm package is changed, which
|
||||
// is rare enough to ignore here).
|
||||
await buildMonaco()
|
||||
await buildMonaco(STATIC_ASSETS_PATH)
|
||||
|
||||
// Start esbuild's server on a random local port.
|
||||
const { host: esbuildHost, port: esbuildPort, wait: esbuildStopped } = await serve(
|
||||
|
||||
@ -243,6 +243,7 @@
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"babel-preset-react-app": "^10.0.0",
|
||||
"browserslist": "^4.17.4",
|
||||
"buffer": "^6.0.3",
|
||||
"bundlesize2": "^0.0.31",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
@ -259,10 +260,12 @@
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"elm": "^0.19.1-3",
|
||||
"elm-webpack-loader": "^8.0.0",
|
||||
"enhanced-resolve": "^5.9.3",
|
||||
"esbuild": "^0.14.2",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-formatter-lsif": "^1.0.3",
|
||||
"eslint-plugin-monorepo": "^0.3.2",
|
||||
"events": "^3.3.0",
|
||||
"execa": "^5.0.0",
|
||||
"express": "^4.17.1",
|
||||
"express-static-gzip": "^2.1.1",
|
||||
@ -325,6 +328,7 @@
|
||||
"speed-measure-webpack-plugin": "^1.5.0",
|
||||
"storybook-addon-designs": "^6.2.1",
|
||||
"storybook-dark-mode": "^1.1.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"string-width": "^4.2.0",
|
||||
"style-loader": "^3.1.0",
|
||||
"stylelint": "^14.3.0",
|
||||
|
||||
32
yarn.lock
32
yarn.lock
@ -8567,6 +8567,14 @@ buffer@^5.2.1, buffer@^5.5.0, buffer@^5.7.0:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
buffer@^6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
||||
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
buffers@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
|
||||
@ -11752,10 +11760,10 @@ engine.io@~3.4.0:
|
||||
engine.io-parser "~2.2.0"
|
||||
ws "^7.1.2"
|
||||
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.9.2:
|
||||
version "5.9.2"
|
||||
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9"
|
||||
integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.9.2, enhanced-resolve@^5.9.3:
|
||||
version "5.9.3"
|
||||
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88"
|
||||
integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.2.0"
|
||||
@ -12528,7 +12536,7 @@ eventemitter3@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
||||
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
|
||||
|
||||
events@^3.2.0:
|
||||
events@^3.2.0, events@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
|
||||
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
||||
@ -14907,7 +14915,7 @@ identity-obj-proxy@^3.0.0:
|
||||
dependencies:
|
||||
harmony-reflect "^1.4.6"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
ieee754@^1.1.13, ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
@ -15030,7 +15038,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@~2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@ -21216,7 +21224,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
@ -22879,6 +22887,14 @@ storybook-dark-mode@^1.1.0:
|
||||
fast-deep-equal "^3.0.0"
|
||||
memoizerific "^1.11.3"
|
||||
|
||||
stream-browserify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f"
|
||||
integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==
|
||||
dependencies:
|
||||
inherits "~2.0.4"
|
||||
readable-stream "^3.5.0"
|
||||
|
||||
stream-exhaust@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user