mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:31:43 +00:00
use esbuild for browser extension builds (#57231)
* move bext-only extension host worker to client/browser * use esbuild for browser extension build esbuild is much faster and simpler than Webpack.
This commit is contained in:
parent
500718ca59
commit
fb3c9c6015
@ -2,7 +2,7 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
|
||||
load("@aspect_rules_js//js:defs.bzl", "js_library")
|
||||
load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
load("//dev:defs.bzl", "jest_test", "sass", "ts_project")
|
||||
load("//dev:webpack.bzl", "webpack_bundle")
|
||||
load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild")
|
||||
load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_operations")
|
||||
load("//client/shared/dev:build_code_intel_extensions.bzl", "build_code_intel_extensions")
|
||||
load("//client/shared/dev:tools.bzl", "module_style_typings")
|
||||
@ -216,6 +216,7 @@ ts_project(
|
||||
"src/shared/components/TrackAnchorClick.tsx",
|
||||
"src/shared/components/WildcardThemeProvider.tsx",
|
||||
"src/shared/context.ts",
|
||||
"src/shared/extensionHostWorker.ts",
|
||||
"src/shared/platform/context.ts",
|
||||
"src/shared/platform/extensionHost.ts",
|
||||
"src/shared/platform/inlineExtensionsService.ts",
|
||||
@ -341,20 +342,19 @@ jest_test(
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "entry-conigs",
|
||||
name = "entry-configs",
|
||||
srcs = glob(["src/config/*.js"]),
|
||||
)
|
||||
|
||||
webpack_bundle(
|
||||
esbuild(
|
||||
name = "bundle",
|
||||
srcs = [
|
||||
# JSON imports
|
||||
"src/browser-extension/manifest.spec.json",
|
||||
"code-intel-extensions.json",
|
||||
|
||||
# SRCS
|
||||
":browser",
|
||||
":entry-conigs",
|
||||
":entry-configs",
|
||||
":module_styles",
|
||||
":package_styles",
|
||||
|
||||
@ -363,24 +363,21 @@ webpack_bundle(
|
||||
"//:browserslist",
|
||||
"//:package_json",
|
||||
|
||||
# STATIC ASSSETS
|
||||
# STATIC ASSETS
|
||||
"//client/browser/assets",
|
||||
],
|
||||
entry_points = {
|
||||
"src/browser-extension/scripts/backgroundPage.main.js": "backgroundPage.main",
|
||||
"src/browser-extension/scripts/contentPage.main.js": "contentPage.main",
|
||||
"src/browser-extension/scripts/optionsPage.main.js": "optionsPage.main",
|
||||
"src/browser-extension/scripts/afterInstallPage.main.js": "afterInstallPage.main",
|
||||
"src/native-integration/nativeIntegration.main.js": "nativeIntegration.main",
|
||||
"src/native-integration/phabricator/phabricatorNativeIntegration.main.js": "phabricatorNativeIntegration.main",
|
||||
"src/app.css": "app",
|
||||
"src/branded.css": "branded",
|
||||
},
|
||||
env = {
|
||||
"NODE_ENV": "production",
|
||||
},
|
||||
output_dir = True,
|
||||
webpack_config = "//client/browser/config:webpack-config",
|
||||
config = "//client/browser/config:esbuild-config",
|
||||
entry_points = [
|
||||
"src/browser-extension/scripts/backgroundPage.main.js",
|
||||
"src/browser-extension/scripts/contentPage.main.js",
|
||||
"src/browser-extension/scripts/optionsPage.main.js",
|
||||
"src/browser-extension/scripts/afterInstallPage.main.js",
|
||||
"src/native-integration/nativeIntegration.main.js",
|
||||
"src/native-integration/phabricator/phabricatorNativeIntegration.main.js",
|
||||
"src/app.css",
|
||||
"src/branded.css",
|
||||
"src/shared/extensionHostWorker.js",
|
||||
],
|
||||
deps = ["//client/browser/config"],
|
||||
)
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ It works as follows:
|
||||
- `shared/`
|
||||
Code shared between multiple code hosts.
|
||||
- `config/`
|
||||
Configuration code that is bundled via webpack. The configuration code adds properties to `window` that make it easier to tell what environment the script is running in. This is useful because the code can be run in the content script, background, options page, or in the actual page when injected by Phabricator and each environment will have different ways to do different things.
|
||||
Configuration code that adds properties to `window` that make it easier to tell what environment the script is running in. This is useful because the code can be run in the content script, background, options page, or in the actual page when injected by Phabricator and each environment will have different ways to do different things.
|
||||
- `end-to-end/`
|
||||
E2E test suite.
|
||||
- `scripts/`
|
||||
@ -59,7 +59,7 @@ It works as follows:
|
||||
- `config/`
|
||||
Build configs.
|
||||
- `build/`
|
||||
Generated directory containing the output from webpack and the generated bundles for each browser.
|
||||
Generated directory containing the build output and the generated bundles for each browser.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@ -9,12 +9,8 @@ load("@aspect_rules_js//js:defs.bzl", "js_library")
|
||||
ts_project(
|
||||
name = "config",
|
||||
srcs = [
|
||||
"webpack/base.config.bazel.ts",
|
||||
"webpack/base.config.ts",
|
||||
"webpack/development.config.ts",
|
||||
"webpack/production.config.bazel.ts",
|
||||
"webpack/production.config.ts",
|
||||
"webpack/utils.ts",
|
||||
"esbuild.ts",
|
||||
"utils.ts",
|
||||
],
|
||||
module = "commonjs",
|
||||
tsconfig = "//client/browser:tsconfig",
|
||||
@ -22,22 +18,21 @@ ts_project(
|
||||
deps = [
|
||||
"//:node_modules/@babel/runtime", #keep
|
||||
"//:node_modules/@types/node",
|
||||
"//:node_modules/css-loader", #keep
|
||||
"//:node_modules/css-minimizer-webpack-plugin",
|
||||
"//:node_modules/mini-css-extract-plugin",
|
||||
"//:node_modules/esbuild",
|
||||
# HACKS: bundle-time css import
|
||||
"//:node_modules/open-color", #keep
|
||||
"//:node_modules/path-browserify", #keep
|
||||
"//:node_modules/style-loader", #keep
|
||||
"//:node_modules/terser-webpack-plugin",
|
||||
"//:node_modules/webpack",
|
||||
"//:node_modules/worker-loader", #keep
|
||||
"//client/browser:node_modules/@sourcegraph/build-config",
|
||||
],
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "webpack-config",
|
||||
srcs = ["webpack/production.config.bazel.js"],
|
||||
name = "esbuild-config",
|
||||
srcs = ["esbuild.bazel.js"],
|
||||
visibility = ["//client:__subpackages__"],
|
||||
deps = [
|
||||
"//client/browser:node_modules/@sourcegraph/build-config",
|
||||
"//client/browser/config",
|
||||
"//client/build-config:build-config_lib",
|
||||
],
|
||||
)
|
||||
|
||||
13
client/browser/config/esbuild.bazel.js
Normal file
13
client/browser/config/esbuild.bazel.js
Normal file
@ -0,0 +1,13 @@
|
||||
// This file is only used by Bazel builds.
|
||||
|
||||
const { esbuildBuildOptions } = require('./esbuild.js')
|
||||
|
||||
module.exports = {
|
||||
...esbuildBuildOptions(process.env.NODE_ENV === 'development' ? 'dev' : 'prod'),
|
||||
|
||||
// Unset configuration properties that are provided by Bazel.
|
||||
entryPoints: undefined,
|
||||
bundle: undefined,
|
||||
outdir: undefined,
|
||||
sourcemap: undefined,
|
||||
}
|
||||
57
client/browser/config/esbuild.ts
Normal file
57
client/browser/config/esbuild.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import path from 'path'
|
||||
|
||||
import type * as esbuild from 'esbuild'
|
||||
|
||||
import { ROOT_PATH, stylePlugin } from '@sourcegraph/build-config'
|
||||
|
||||
import { generateBundleUID } from './utils'
|
||||
|
||||
const browserWorkspacePath = path.resolve(ROOT_PATH, 'client/browser')
|
||||
const browserSourcePath = path.resolve(browserWorkspacePath, 'src')
|
||||
|
||||
/**
|
||||
* Returns the esbuild build options for the browser extension build.
|
||||
*/
|
||||
export function esbuildBuildOptions(mode: 'dev' | 'prod', extraPlugins: esbuild.Plugin[] = []): esbuild.BuildOptions {
|
||||
return {
|
||||
entryPoints: [
|
||||
// Browser extension
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/backgroundPage.main.ts'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/contentPage.main.ts'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/optionsPage.main.tsx'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/afterInstallPage.main.tsx'),
|
||||
|
||||
// Common native integration entry point (Gitlab, Bitbucket)
|
||||
path.resolve(browserSourcePath, 'native-integration/nativeIntegration.main.ts'),
|
||||
// Phabricator-only native integration entry point
|
||||
path.resolve(browserSourcePath, 'native-integration/phabricator/phabricatorNativeIntegration.main.ts'),
|
||||
|
||||
// Styles
|
||||
path.join(browserSourcePath, 'app.scss'),
|
||||
path.join(browserSourcePath, 'branded.scss'),
|
||||
|
||||
// Worker
|
||||
path.resolve(browserSourcePath, 'shared/extensionHostWorker.ts'),
|
||||
],
|
||||
format: 'cjs',
|
||||
platform: 'browser',
|
||||
plugins: [stylePlugin, ...extraPlugins],
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(mode === 'dev' ? 'development' : 'production'),
|
||||
'process.env.BUNDLE_UID': JSON.stringify(generateBundleUID()),
|
||||
},
|
||||
bundle: true,
|
||||
minify: false,
|
||||
logLevel: 'error',
|
||||
jsx: 'automatic',
|
||||
outdir: path.join(browserWorkspacePath, 'build/dist'),
|
||||
chunkNames: '[ext]/[hash].chunk',
|
||||
entryNames: '[ext]/[name].bundle',
|
||||
target: 'esnext',
|
||||
sourcemap: true,
|
||||
alias: { path: 'path-browserify' },
|
||||
loader: {
|
||||
'.svg': 'text',
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import path from 'path'
|
||||
|
||||
import CssMinimizerWebpackPlugin from 'css-minimizer-webpack-plugin'
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
||||
import webpack, { optimize } from 'webpack'
|
||||
|
||||
import {
|
||||
getBazelCSSLoaders as getCSSLoaders,
|
||||
getProvidePlugin,
|
||||
getTerserPlugin,
|
||||
getBasicCSSLoader,
|
||||
getCSSModulesLoader,
|
||||
} from '@sourcegraph/build-config'
|
||||
|
||||
const browserWorkspacePath = path.resolve(process.cwd(), 'client/browser')
|
||||
|
||||
const JS_OUTPUT_FOLDER = 'scripts'
|
||||
const CSS_OUTPUT_FOLDER = 'css'
|
||||
|
||||
const extensionHostWorker = /main\.worker\.js$/
|
||||
|
||||
export const config = {
|
||||
stats: {
|
||||
children: true,
|
||||
},
|
||||
target: 'browserslist',
|
||||
output: {
|
||||
path: path.join(browserWorkspacePath, 'build/dist/js'),
|
||||
filename: `${JS_OUTPUT_FOLDER}/[name].bundle.js`,
|
||||
chunkFilename: '[id].chunk.js',
|
||||
},
|
||||
devtool: 'inline-cheap-module-source-map',
|
||||
optimization: {
|
||||
minimizer: [getTerserPlugin() as webpack.WebpackPluginInstance, new CssMinimizerWebpackPlugin()],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
// Change scss imports to the pre-compiled css files
|
||||
new webpack.NormalModuleReplacementPlugin(/.*\.scss$/, resource => {
|
||||
resource.request = resource.request.replace(/\.scss$/, '.css')
|
||||
}),
|
||||
new MiniCssExtractPlugin({ filename: `${CSS_OUTPUT_FOLDER}/[name].bundle.css` }),
|
||||
// Code splitting doesn't make sense/work in the browser extension, but we still want to use dynamic import()
|
||||
new optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
||||
getProvidePlugin(),
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
alias: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
exclude: extensionHostWorker,
|
||||
type: 'javascript/auto',
|
||||
resolve: {
|
||||
// Allow importing without file extensions
|
||||
// https://webpack.js.org/configuration/module/#resolvefullyspecified
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
// SCSS rule for our own and third-party styles
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: getCSSLoaders(MiniCssExtractPlugin.loader, getBasicCSSLoader()),
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
// CSS Modules loaders are only applied when the file is explicitly named as CSS module stylesheet using the extension `.module.scss`.
|
||||
include: /\.module\.css$/,
|
||||
use: getCSSLoaders(MiniCssExtractPlugin.loader, getCSSModulesLoader({ sourceMap: false, url: false })),
|
||||
},
|
||||
{
|
||||
test: /\.svg$/i,
|
||||
type: 'asset/inline',
|
||||
},
|
||||
{
|
||||
test: extensionHostWorker,
|
||||
use: [
|
||||
{
|
||||
loader: 'worker-loader',
|
||||
options: { filename: `${JS_OUTPUT_FOLDER}/extensionHostWorker.bundle.js` },
|
||||
},
|
||||
],
|
||||
resolve: {
|
||||
// Allow importing without file extensions
|
||||
// https://webpack.js.org/configuration/module/#resolvefullyspecified
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} satisfies webpack.Configuration
|
||||
@ -1,97 +0,0 @@
|
||||
import path from 'path'
|
||||
|
||||
import CssMinimizerWebpackPlugin from 'css-minimizer-webpack-plugin'
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
||||
import type webpack from 'webpack'
|
||||
import { optimize } from 'webpack'
|
||||
|
||||
import {
|
||||
ROOT_PATH,
|
||||
getBabelLoader,
|
||||
getCSSLoaders,
|
||||
getProvidePlugin,
|
||||
getTerserPlugin,
|
||||
getCSSModulesLoader,
|
||||
getBasicCSSLoader,
|
||||
} from '@sourcegraph/build-config'
|
||||
|
||||
export const browserWorkspacePath = path.resolve(ROOT_PATH, 'client/browser')
|
||||
const browserSourcePath = path.resolve(browserWorkspacePath, 'src')
|
||||
|
||||
const extensionHostWorker = /main\.worker\.ts$/
|
||||
|
||||
export const config = {
|
||||
target: 'browserslist',
|
||||
entry: [
|
||||
// Browser extension
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/backgroundPage.main.ts'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/contentPage.main.ts'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/optionsPage.main.tsx'),
|
||||
path.resolve(browserSourcePath, 'browser-extension/scripts/afterInstallPage.main.tsx'),
|
||||
|
||||
// Common native integration entry point (Gitlab, Bitbucket)
|
||||
path.resolve(browserSourcePath, 'native-integration/nativeIntegration.main.ts'),
|
||||
// Phabricator-only native integration entry point
|
||||
path.resolve(browserSourcePath, 'native-integration/phabricator/phabricatorNativeIntegration.main.ts'),
|
||||
|
||||
// Styles
|
||||
path.join(browserSourcePath, 'app.scss'),
|
||||
path.join(browserSourcePath, 'branded.scss'),
|
||||
],
|
||||
output: {
|
||||
path: path.join(browserWorkspacePath, 'build/dist/js'),
|
||||
filename: '[name].bundle.js',
|
||||
chunkFilename: '[id].chunk.js',
|
||||
},
|
||||
devtool: 'inline-cheap-module-source-map',
|
||||
optimization: {
|
||||
minimizer: [getTerserPlugin() as webpack.WebpackPluginInstance, new CssMinimizerWebpackPlugin()],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({ filename: '../css/[name].bundle.css' }),
|
||||
// Code splitting doesn't make sense/work in the browser extension, but we still want to use dynamic import()
|
||||
new optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
||||
getProvidePlugin(),
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
alias: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.[jt]sx?$/,
|
||||
exclude: extensionHostWorker,
|
||||
use: [getBabelLoader()],
|
||||
},
|
||||
{
|
||||
// SCSS rule for our own and third-party styles
|
||||
test: /\.(css|sass|scss)$/,
|
||||
exclude: /\.module\.(sass|scss)$/,
|
||||
use: getCSSLoaders(MiniCssExtractPlugin.loader, getBasicCSSLoader()),
|
||||
},
|
||||
{
|
||||
test: /\.(css|sass|scss)$/,
|
||||
include: /\.module\.(sass|scss)$/,
|
||||
use: getCSSLoaders(MiniCssExtractPlugin.loader, getCSSModulesLoader({ sourceMap: false, url: false })),
|
||||
},
|
||||
{
|
||||
test: /\.svg$/i,
|
||||
type: 'asset/inline',
|
||||
},
|
||||
{
|
||||
test: extensionHostWorker,
|
||||
use: [
|
||||
{
|
||||
loader: 'worker-loader',
|
||||
options: { filename: 'extensionHostWorker.bundle.js' },
|
||||
},
|
||||
getBabelLoader(),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
} satisfies webpack.Configuration
|
||||
@ -1,27 +0,0 @@
|
||||
import * as path from 'path'
|
||||
|
||||
import * as webpack from 'webpack'
|
||||
|
||||
import { getCacheConfig } from '@sourcegraph/build-config'
|
||||
|
||||
import { config as baseConfig, browserWorkspacePath } from './base.config'
|
||||
import { generateBundleUID } from './utils'
|
||||
|
||||
const { plugins, ...base } = baseConfig
|
||||
|
||||
export const config: webpack.Configuration = {
|
||||
...base,
|
||||
mode: 'development',
|
||||
// Use cache only in `development` mode to speed up production build.
|
||||
cache: getCacheConfig({ invalidateCacheFiles: [path.resolve(browserWorkspacePath, 'babel.config.js')] }),
|
||||
plugins: (plugins || []).concat(
|
||||
...[
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('development'),
|
||||
BUNDLE_UID: JSON.stringify(generateBundleUID()),
|
||||
},
|
||||
}),
|
||||
]
|
||||
),
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
import TerserPlugin from 'terser-webpack-plugin'
|
||||
import * as webpack from 'webpack'
|
||||
|
||||
import { config as baseConfig } from './base.config.bazel'
|
||||
import { generateBundleUID } from './utils'
|
||||
|
||||
const { plugins, ...base } = baseConfig
|
||||
|
||||
export const config: webpack.Configuration = {
|
||||
...base,
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
extractComments: false,
|
||||
terserOptions: {
|
||||
output: {
|
||||
// Without this, Uglify will change \u0000 to \0 (NULL byte),
|
||||
// which causes Chrome to complain that the bundle is not UTF8
|
||||
ascii_only: true,
|
||||
beautify: false,
|
||||
comments: false,
|
||||
},
|
||||
},
|
||||
}) as webpack.WebpackPluginInstance,
|
||||
],
|
||||
},
|
||||
plugins: (plugins || []).concat(
|
||||
...[
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('production'),
|
||||
BUNDLE_UID: JSON.stringify(generateBundleUID()),
|
||||
},
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
'$.fn.pjax': 'jquery-pjax',
|
||||
}),
|
||||
]
|
||||
),
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default config
|
||||
@ -1,44 +0,0 @@
|
||||
import TerserPlugin from 'terser-webpack-plugin'
|
||||
import * as webpack from 'webpack'
|
||||
|
||||
import { config as baseConfig } from './base.config'
|
||||
import { generateBundleUID } from './utils'
|
||||
|
||||
const { plugins, ...base } = baseConfig
|
||||
|
||||
export const config: webpack.Configuration = {
|
||||
...base,
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
extractComments: false,
|
||||
terserOptions: {
|
||||
output: {
|
||||
// Without this, Uglify will change \u0000 to \0 (NULL byte),
|
||||
// which causes Chrome to complain that the bundle is not UTF8
|
||||
ascii_only: true,
|
||||
beautify: false,
|
||||
comments: false,
|
||||
},
|
||||
},
|
||||
}) as webpack.WebpackPluginInstance,
|
||||
],
|
||||
},
|
||||
plugins: (plugins || []).concat(
|
||||
...[
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('production'),
|
||||
BUNDLE_UID: JSON.stringify(generateBundleUID()),
|
||||
},
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
'$.fn.pjax': 'jquery-pjax',
|
||||
}),
|
||||
]
|
||||
),
|
||||
}
|
||||
@ -1,45 +1,16 @@
|
||||
import shelljs from 'shelljs'
|
||||
import signale from 'signale'
|
||||
import webpack from 'webpack'
|
||||
import * as esbuild from 'esbuild'
|
||||
|
||||
import { config } from '../config/webpack/production.config'
|
||||
import { esbuildBuildOptions } from '../config/esbuild'
|
||||
|
||||
import { buildNpm } from './build-npm'
|
||||
import * as tasks from './tasks'
|
||||
import { browserBuildStepsPlugin, copyAssetsPlugin } from './esbuildPlugins'
|
||||
|
||||
const buildChrome = tasks.buildChrome('prod')
|
||||
const buildFirefox = tasks.buildFirefox('prod')
|
||||
const buildSafari = tasks.buildSafari('prod')
|
||||
const buildEdge = tasks.buildEdge('prod')
|
||||
|
||||
tasks.copyAssets()
|
||||
|
||||
const compiler = webpack(config)
|
||||
|
||||
signale.await('Webpack compilation')
|
||||
|
||||
compiler.run(async (error, stats) => {
|
||||
console.log(stats?.toString(tasks.WEBPACK_STATS_OPTIONS))
|
||||
|
||||
if (stats?.hasErrors()) {
|
||||
signale.error('Webpack compilation error')
|
||||
process.exit(1)
|
||||
}
|
||||
signale.success('Webpack compilation done')
|
||||
|
||||
buildChrome()
|
||||
buildEdge()
|
||||
buildFirefox()
|
||||
if (isXcodeAvailable()) {
|
||||
buildSafari()
|
||||
} else {
|
||||
signale.debug('Skipping Safari build because Xcode tools were not found (xcrun, xcodebuild)')
|
||||
}
|
||||
tasks.copyIntegrationAssets()
|
||||
await buildNpm()
|
||||
signale.success('Build done')
|
||||
})
|
||||
|
||||
function isXcodeAvailable(): boolean {
|
||||
return !!shelljs.which('xcrun') && !!shelljs.which('xcodebuild')
|
||||
async function build(): Promise<void> {
|
||||
await esbuild.build(esbuildBuildOptions('prod', [copyAssetsPlugin, browserBuildStepsPlugin('prod')]))
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
build().catch(error => {
|
||||
console.error('Error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,40 +1,20 @@
|
||||
import * as esbuild from 'esbuild'
|
||||
import signale from 'signale'
|
||||
import webpack from 'webpack'
|
||||
|
||||
import { config } from '../config/webpack/development.config'
|
||||
import { esbuildBuildOptions } from '../config/esbuild'
|
||||
|
||||
import * as tasks from './tasks'
|
||||
import { browserBuildStepsPlugin, copyAssetsPlugin } from './esbuildPlugins'
|
||||
|
||||
signale.config({ displayTimestamp: true })
|
||||
async function watch(): Promise<void> {
|
||||
const ctx = await esbuild.context(esbuildBuildOptions('dev', [copyAssetsPlugin, browserBuildStepsPlugin('dev')]))
|
||||
await ctx.watch()
|
||||
signale.info('Watching...')
|
||||
await new Promise(() => {}) // wait forever
|
||||
}
|
||||
|
||||
const buildChrome = tasks.buildChrome('dev')
|
||||
const buildFirefox = tasks.buildFirefox('dev')
|
||||
const buildEdge = tasks.buildEdge('dev')
|
||||
|
||||
tasks.copyAssets()
|
||||
|
||||
const compiler = webpack(config)
|
||||
|
||||
signale.info('Running webpack')
|
||||
|
||||
compiler.hooks.watchRun.tap('Notify', () => signale.await('Compiling...'))
|
||||
|
||||
compiler.watch(
|
||||
{
|
||||
aggregateTimeout: 300,
|
||||
},
|
||||
(error, stats) => {
|
||||
signale.complete(stats?.toString(tasks.WEBPACK_STATS_OPTIONS))
|
||||
|
||||
if (error || stats?.hasErrors()) {
|
||||
signale.error('Webpack compilation error')
|
||||
return
|
||||
}
|
||||
signale.success('Webpack compilation done')
|
||||
|
||||
buildChrome()
|
||||
buildEdge()
|
||||
buildFirefox()
|
||||
tasks.copyIntegrationAssets()
|
||||
}
|
||||
)
|
||||
if (require.main === module) {
|
||||
watch().catch(error => {
|
||||
console.error('Error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
46
client/browser/scripts/esbuildPlugins.ts
Normal file
46
client/browser/scripts/esbuildPlugins.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import type * as esbuild from 'esbuild'
|
||||
import shelljs from 'shelljs'
|
||||
import signale from 'signale'
|
||||
|
||||
import { buildNpm } from './build-npm'
|
||||
import * as tasks from './tasks'
|
||||
|
||||
export const copyAssetsPlugin: esbuild.Plugin = {
|
||||
name: 'copyAssets',
|
||||
setup: (): void => {
|
||||
tasks.copyAssets()
|
||||
},
|
||||
}
|
||||
|
||||
export function browserBuildStepsPlugin(mode: 'dev' | 'prod'): esbuild.Plugin {
|
||||
return {
|
||||
name: 'browserBuildSteps',
|
||||
setup: (build: esbuild.PluginBuild): void => {
|
||||
build.onEnd(async result => {
|
||||
if (result.errors.length === 0) {
|
||||
signale.info('Running browser build steps...')
|
||||
tasks.buildChrome(mode)()
|
||||
tasks.buildFirefox(mode)()
|
||||
tasks.buildEdge(mode)()
|
||||
if (mode === 'prod') {
|
||||
if (isXcodeAvailable()) {
|
||||
tasks.buildSafari(mode)()
|
||||
} else {
|
||||
signale.debug(
|
||||
'Skipping Safari build because Xcode tools were not found (xcrun, xcodebuild)'
|
||||
)
|
||||
}
|
||||
}
|
||||
tasks.copyIntegrationAssets()
|
||||
if (mode === 'prod') {
|
||||
await buildNpm()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function isXcodeAvailable(): boolean {
|
||||
return !!shelljs.which('xcrun') && !!shelljs.which('xcodebuild')
|
||||
}
|
||||
@ -6,7 +6,6 @@ import { omit, cloneDeep, curry } from 'lodash'
|
||||
import shelljs from 'shelljs'
|
||||
import signale from 'signale'
|
||||
import utcVersion from 'utc-version'
|
||||
import type { Configuration } from 'webpack'
|
||||
|
||||
import manifestSpec from '../src/browser-extension/manifest.spec.json'
|
||||
import schema from '../src/browser-extension/schema.json'
|
||||
@ -20,7 +19,7 @@ const EXTENSION_PERMISSIONS_ALL_URLS = Boolean(
|
||||
process.env.EXTENSION_PERMISSIONS_ALL_URLS && JSON.parse(process.env.EXTENSION_PERMISSIONS_ALL_URLS)
|
||||
)
|
||||
|
||||
export type BuildEnvironment = 'dev' | 'prod'
|
||||
type BuildEnvironment = 'dev' | 'prod'
|
||||
|
||||
type Browser = 'firefox' | 'chrome' | 'safari' | 'edge'
|
||||
|
||||
@ -37,14 +36,6 @@ const BUILDS_DIR = 'build'
|
||||
*/
|
||||
const useUtcVersion = true
|
||||
|
||||
export const WEBPACK_STATS_OPTIONS: Configuration['stats'] = {
|
||||
all: false,
|
||||
timings: true,
|
||||
errors: true,
|
||||
warnings: true,
|
||||
colors: true,
|
||||
}
|
||||
|
||||
function ensurePaths(browser?: Browser): void {
|
||||
shelljs.mkdir('-p', 'build/dist')
|
||||
shelljs.mkdir('-p', 'build/bundles')
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import '../../polyfills'
|
||||
import '@sourcegraph/shared/src/polyfills'
|
||||
|
||||
import { fromEvent } from 'rxjs'
|
||||
import { take } from 'rxjs/operators'
|
||||
|
||||
import { hasProperty, logger } from '@sourcegraph/common'
|
||||
|
||||
import { isEndpointPair } from '../../platform/context'
|
||||
|
||||
import { startExtensionHost } from './extensionHost'
|
||||
import { startExtensionHost } from '@sourcegraph/shared/src/api/extension/extensionHost'
|
||||
import { isEndpointPair } from '@sourcegraph/shared/src/platform/context'
|
||||
|
||||
interface InitMessage {
|
||||
endpoints: {
|
||||
@ -3,8 +3,8 @@ load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
load("//dev:defs.bzl", "npm_package", "ts_project")
|
||||
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
|
||||
|
||||
# TODO(bazel): currently handled with #keep
|
||||
# gazelle:js_resolve **/esbuild/* //client/build-config/src/esbuild
|
||||
# gazelle:js_ignore_imports ../../../../postcss.config
|
||||
# gazelle:js_ignore_imports ../../../../../../../../postcss.config
|
||||
|
||||
npm_link_all_packages(name = "node_modules")
|
||||
|
||||
@ -22,6 +22,11 @@ ts_config(
|
||||
ts_project(
|
||||
name = "build-config_lib",
|
||||
srcs = [
|
||||
"src/esbuild/monacoPlugin.ts",
|
||||
"src/esbuild/packageResolutionPlugin.ts",
|
||||
"src/esbuild/plugins.ts",
|
||||
"src/esbuild/stylePlugin.ts",
|
||||
"src/esbuild/workerPlugin.ts",
|
||||
"src/index.ts",
|
||||
"src/paths.ts",
|
||||
"src/utils/environment-config.ts",
|
||||
@ -35,10 +40,16 @@ ts_project(
|
||||
tsconfig = ":tsconfig",
|
||||
deps = [
|
||||
":node_modules/@statoscope/webpack-plugin",
|
||||
":node_modules/@types/sass",
|
||||
":node_modules/buffer", #keep
|
||||
":node_modules/css-loader", #keep
|
||||
":node_modules/enhanced-resolve",
|
||||
":node_modules/esbuild",
|
||||
":node_modules/monaco-editor-webpack-plugin",
|
||||
":node_modules/postcss",
|
||||
":node_modules/postcss-modules",
|
||||
":node_modules/process", #keep
|
||||
":node_modules/sass",
|
||||
":node_modules/style-loader", #keep
|
||||
":node_modules/terser-webpack-plugin",
|
||||
":node_modules/webpack",
|
||||
@ -48,7 +59,6 @@ ts_project(
|
||||
"//:node_modules/@types/node",
|
||||
"//:node_modules/monaco-editor", #keep
|
||||
"//:node_modules/monaco-yaml", #keep
|
||||
"//client/build-config/src/esbuild",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
# TODO(bazel): esbuild build disabled, mocked for now
|
||||
|
||||
load("@aspect_rules_js//js:defs.bzl", "js_library")
|
||||
|
||||
genrule(
|
||||
name = "esbuild-mocked",
|
||||
outs = ["plugins.js"],
|
||||
cmd = "echo 'exports.stylePlugin = {}' > $@",
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "esbuild-mocked-types",
|
||||
outs = ["plugins.d.ts"],
|
||||
cmd = "echo 'export const stylePlugin: any' > $@",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "esbuild",
|
||||
srcs = [
|
||||
":esbuild-mocked",
|
||||
":esbuild-mocked-types",
|
||||
],
|
||||
visibility = ["//client/build-config:__pkg__"],
|
||||
)
|
||||
@ -7,17 +7,24 @@ import postcss from 'postcss'
|
||||
import postcssModules from 'postcss-modules'
|
||||
import sass from 'sass'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
import postcssConfig from '../../../../postcss.config'
|
||||
import { NODE_MODULES_PATH, ROOT_PATH, WORKSPACE_NODE_MODULES_PATHS } from '../paths'
|
||||
|
||||
/* eslint-disable import/extensions */
|
||||
|
||||
const postcssConfig = process.env.BAZEL_BINDIR
|
||||
? // eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('../../../../../../../../postcss.config')
|
||||
: // eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('../../../../postcss.config')
|
||||
|
||||
/**
|
||||
* An esbuild plugin that builds .css and .scss stylesheets (including support for CSS modules).
|
||||
*/
|
||||
export const stylePlugin: esbuild.Plugin = {
|
||||
name: 'style',
|
||||
setup: build => {
|
||||
const isBazel = process.env.BAZEL_BINDIR
|
||||
|
||||
const modulesMap = new Map<string, string>()
|
||||
const modulesPlugin = postcssModules({
|
||||
generateScopedName: '[name]__[local]', // omit hash for local dev
|
||||
@ -105,13 +112,19 @@ export const stylePlugin: esbuild.Plugin = {
|
||||
unsafeCache: true,
|
||||
})
|
||||
|
||||
build.onResolve({ filter: /\.s?css$/, namespace: 'file' }, async args => {
|
||||
build.onResolve({ filter: /\.s?css$/, namespace: 'file' }, async ({ path: argsPath, ...args }) => {
|
||||
// If running in Bazel, assume that the SASS compiler has already been run and just
|
||||
// import the `.css` file.
|
||||
if (isBazel) {
|
||||
argsPath = argsPath.replace(/\.scss$/, '.css')
|
||||
}
|
||||
|
||||
const inputPath = await new Promise<string>((resolve, reject) => {
|
||||
resolver.resolve({}, args.resolveDir, args.path, {}, (error, filepath) => {
|
||||
resolver.resolve({}, args.resolveDir, argsPath, {}, (error, filepath) => {
|
||||
if (filepath) {
|
||||
resolve(filepath)
|
||||
} else {
|
||||
reject(error ?? new Error(`Could not resolve file path for ${args.path}`))
|
||||
reject(error ?? new Error(`Could not resolve file path for ${argsPath}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -154,7 +154,6 @@ ts_project(
|
||||
"src/api/extension/extensionHost.ts",
|
||||
"src/api/extension/extensionHostApi.ts",
|
||||
"src/api/extension/extensionHostState.ts",
|
||||
"src/api/extension/main.worker.ts",
|
||||
"src/api/extension/test/test-helpers.ts",
|
||||
"src/api/extension/util.ts",
|
||||
"src/api/extension/utils/ReferenceCounter.ts",
|
||||
|
||||
@ -1,24 +1,12 @@
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
import type { EndpointPair, ClosableEndpointPair } from '../../platform/context'
|
||||
|
||||
/* eslint-disable import/extensions, @typescript-eslint/ban-ts-comment */
|
||||
// @ts-ignore
|
||||
import ExtensionHostWorker from './main.worker'
|
||||
|
||||
/* eslint-enable import/extensions, @typescript-eslint/ban-ts-comment */
|
||||
import type { EndpointPair } from '../../platform/context'
|
||||
|
||||
/**
|
||||
* Creates a web worker with the extension host and sets up a bidirectional MessageChannel-based communication channel.
|
||||
*
|
||||
* If a `workerBundleURL` is provided, it is used to create a new Worker(), instead of using the ExtensionHostWorker
|
||||
* returned by worker-loader. This is useful to load the worker bundle from a different path.
|
||||
*/
|
||||
export function createExtensionHostWorker(workerBundleURL?: string): { worker: Worker; clientEndpoints: EndpointPair } {
|
||||
export function createExtensionHostWorker(workerBundleURL: string): { worker: Worker; clientEndpoints: EndpointPair } {
|
||||
const clientAPIChannel = new MessageChannel()
|
||||
const extensionHostAPIChannel = new MessageChannel()
|
||||
const worker = workerBundleURL ? new Worker(workerBundleURL) : new ExtensionHostWorker()
|
||||
const worker = new Worker(workerBundleURL)
|
||||
const workerEndpoints: EndpointPair = {
|
||||
proxy: clientAPIChannel.port2,
|
||||
expose: extensionHostAPIChannel.port2,
|
||||
@ -30,8 +18,3 @@ export function createExtensionHostWorker(workerBundleURL?: string): { worker: W
|
||||
}
|
||||
return { worker, clientEndpoints }
|
||||
}
|
||||
|
||||
export function createExtensionHost(workerBundleURL?: string): ClosableEndpointPair {
|
||||
const { clientEndpoints, worker } = createExtensionHostWorker(workerBundleURL)
|
||||
return { endpoints: clientEndpoints, subscription: new Subscription(() => worker.terminate()) }
|
||||
}
|
||||
|
||||
@ -2100,6 +2100,7 @@ WEBPACK_CONFIG_DEPS = [
|
||||
"//:node_modules/react-refresh",
|
||||
"//client/web/dev",
|
||||
"//:node_modules/react-visibility-sensor", # required for https://github.com/joshwnj/react-visibility-sensor/issues/148 workaround
|
||||
"//:postcss_config_js",
|
||||
|
||||
# HACKS: bundle-time css import
|
||||
"//:node_modules/open-color",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user