mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 19:21:50 +00:00
222 lines
6.7 KiB
JavaScript
222 lines
6.7 KiB
JavaScript
const path = require('path')
|
|
|
|
require('ts-node').register({
|
|
transpileOnly: true,
|
|
// Use config with "module": "commonjs" because not all modules involved in tasks are esnext modules.
|
|
project: path.resolve(__dirname, './dev/tsconfig.json'),
|
|
})
|
|
|
|
const compression = require('compression')
|
|
const gulp = require('gulp')
|
|
const { createProxyMiddleware } = require('http-proxy-middleware')
|
|
const signale = require('signale')
|
|
const createWebpackCompiler = require('webpack')
|
|
const WebpackDevServer = require('webpack-dev-server')
|
|
|
|
const {
|
|
graphQlOperations,
|
|
schema,
|
|
watchGraphQlOperations,
|
|
watchSchema,
|
|
cssModulesTypings,
|
|
watchCSSModulesTypings,
|
|
} = require('../shared/gulpfile')
|
|
|
|
const { build: buildEsbuild } = require('./dev/esbuild/build')
|
|
const { esbuildDevelopmentServer } = require('./dev/esbuild/server')
|
|
const {
|
|
ENVIRONMENT_CONFIG,
|
|
HTTPS_WEB_SERVER_URL,
|
|
WEBPACK_STATS_OPTIONS,
|
|
DEV_SERVER_LISTEN_ADDR,
|
|
DEV_SERVER_PROXY_TARGET_ADDR,
|
|
shouldCompressResponse,
|
|
printSuccessBanner,
|
|
} = require('./dev/utils')
|
|
const webpackConfig = require('./webpack.config')
|
|
|
|
const { DEV_WEB_BUILDER, SOURCEGRAPH_HTTPS_DOMAIN, SOURCEGRAPH_HTTPS_PORT } = ENVIRONMENT_CONFIG
|
|
|
|
/**
|
|
* @param {import('webpack').Stats} stats
|
|
*/
|
|
const logWebpackStats = stats => {
|
|
signale.info(stats.toString(WEBPACK_STATS_OPTIONS))
|
|
}
|
|
|
|
function createWebApplicationCompiler() {
|
|
signale.info('Building web application with the environment config', ENVIRONMENT_CONFIG)
|
|
|
|
return createWebpackCompiler(webpackConfig)
|
|
}
|
|
|
|
async function webpack() {
|
|
const compiler = createWebApplicationCompiler()
|
|
/** @type {import('webpack').Stats} */
|
|
const stats = await new Promise((resolve, reject) => {
|
|
compiler.run((error, stats) => (error ? reject(error) : resolve(stats)))
|
|
})
|
|
logWebpackStats(stats)
|
|
if (stats.hasErrors()) {
|
|
throw Object.assign(new Error('Failed to compile'), { showStack: false })
|
|
}
|
|
}
|
|
|
|
const webBuild = DEV_WEB_BUILDER === 'webpack' ? webpack : buildEsbuild
|
|
|
|
/**
|
|
* Watch files and update the webpack bundle on disk without starting a dev server.
|
|
*/
|
|
async function watchWebpack() {
|
|
const compiler = createWebApplicationCompiler()
|
|
compiler.hooks.watchRun.tap('Notify', () => signale.info('Webpack compiling...'))
|
|
await new Promise(() => {
|
|
compiler.watch({ aggregateTimeout: 300 }, (error, stats) => {
|
|
logWebpackStats(stats)
|
|
if (error || stats.hasErrors()) {
|
|
signale.error('Webpack compilation error')
|
|
} else {
|
|
signale.info('Webpack compilation done')
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
async function webpackDevelopmentServer() {
|
|
const start = performance.now()
|
|
|
|
/** @type {import('webpack-dev-server').ProxyConfigMap } */
|
|
const proxyConfig = {
|
|
'/': {
|
|
target: `http://${DEV_SERVER_PROXY_TARGET_ADDR.host}:${DEV_SERVER_PROXY_TARGET_ADDR.port}`,
|
|
// Avoid crashing on "read ECONNRESET".
|
|
onError: () => undefined,
|
|
// Don't log proxy errors, these usually just contain
|
|
// ECONNRESET errors caused by the browser cancelling
|
|
// requests. This should not be needed to actually debug something.
|
|
logLevel: 'silent',
|
|
onProxyReqWs: (_proxyRequest, _request, socket) =>
|
|
socket.on('error', error => console.error('WebSocket proxy error:', error)),
|
|
},
|
|
}
|
|
|
|
/** @type {import('webpack-dev-server').Configuration} */
|
|
const options = {
|
|
// react-refresh plugin triggers page reload if needed.
|
|
liveReload: false,
|
|
hot: true,
|
|
host: DEV_SERVER_LISTEN_ADDR.host,
|
|
port: DEV_SERVER_LISTEN_ADDR.port,
|
|
// Disable default DevServer compression. We need more fine grained compression to support streaming search.
|
|
compress: false,
|
|
setupMiddlewares: (middlewares, developmentServer) => {
|
|
// Re-enable gzip compression using our own `compression` filter.
|
|
developmentServer.app.use(compression({ filter: shouldCompressResponse }))
|
|
return middlewares
|
|
},
|
|
client: {
|
|
overlay: false,
|
|
webSocketTransport: 'ws',
|
|
logging: 'verbose',
|
|
webSocketURL: {
|
|
hostname: SOURCEGRAPH_HTTPS_DOMAIN,
|
|
port: SOURCEGRAPH_HTTPS_PORT,
|
|
protocol: 'wss',
|
|
},
|
|
},
|
|
static: {
|
|
directory: './ui/assets',
|
|
publicPath: '/.assets/',
|
|
},
|
|
proxy: proxyConfig,
|
|
webSocketServer: 'ws',
|
|
}
|
|
|
|
const compiler = createWebApplicationCompiler()
|
|
let compilationDoneOnce = false
|
|
compiler.hooks.done.tap('Print external URL', stats => {
|
|
stats = stats.toJson()
|
|
if (stats.errors !== undefined && stats.errors.length > 0) {
|
|
// show errors
|
|
return
|
|
}
|
|
if (compilationDoneOnce) {
|
|
return
|
|
}
|
|
compilationDoneOnce = true
|
|
|
|
signale.info(`Webpack server is ready after ${Math.round(performance.now() - start)}ms`)
|
|
printSuccessBanner(['✱ Sourcegraph is really ready now!', `Click here: ${HTTPS_WEB_SERVER_URL}`])
|
|
})
|
|
|
|
const server = new WebpackDevServer(options, compiler)
|
|
signale.await('Waiting for Webpack to compile assets')
|
|
await server.start()
|
|
}
|
|
|
|
const esbuildDevelopmentProxy = () =>
|
|
esbuildDevelopmentServer(DEV_SERVER_LISTEN_ADDR, app => {
|
|
app.use(
|
|
'/',
|
|
createProxyMiddleware({
|
|
target: {
|
|
protocol: 'http:',
|
|
host: DEV_SERVER_PROXY_TARGET_ADDR.host,
|
|
port: DEV_SERVER_PROXY_TARGET_ADDR.port,
|
|
},
|
|
logLevel: 'error',
|
|
})
|
|
)
|
|
})
|
|
|
|
const developmentServer = DEV_WEB_BUILDER === 'webpack' ? webpackDevelopmentServer : esbuildDevelopmentProxy
|
|
|
|
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
|
|
const generate = gulp.parallel(schema, graphQlOperations, cssModulesTypings)
|
|
|
|
// Watches code generation only, rebuilds on file changes
|
|
const watchGenerators = gulp.parallel(watchSchema, watchGraphQlOperations, watchCSSModulesTypings)
|
|
|
|
/**
|
|
* Builds everything.
|
|
*/
|
|
const build = gulp.series(generate, webBuild)
|
|
|
|
/**
|
|
* Starts a development server without initial code generation, watches everything and rebuilds on file changes.
|
|
*/
|
|
const developmentWithoutInitialCodeGen = gulp.parallel(watchGenerators, developmentServer)
|
|
|
|
/**
|
|
* Runs code generation first, then starts a development server, watches everything and rebuilds on file changes.
|
|
*/
|
|
const development = gulp.series(
|
|
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
|
|
generate,
|
|
developmentWithoutInitialCodeGen
|
|
)
|
|
|
|
/**
|
|
* Watches everything, rebuilds on file changes and writes the bundle to disk.
|
|
* Useful to running integration tests.
|
|
*/
|
|
const watch = gulp.series(
|
|
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
|
|
generate,
|
|
gulp.parallel(watchGenerators, watchWebpack)
|
|
)
|
|
|
|
module.exports = {
|
|
build,
|
|
watch,
|
|
dev: development,
|
|
unsafeDev: developmentWithoutInitialCodeGen,
|
|
webpackDevServer: webpackDevelopmentServer,
|
|
webpack,
|
|
watchWebpack,
|
|
webBuild,
|
|
developmentServer,
|
|
generate,
|
|
watchGenerators,
|
|
}
|