diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 1a78039efd..d8aad7945f 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -28,6 +28,7 @@ }, "dependencies": { "@types/stoppable": "^1.1.0", + "@types/webpack-env": "^1.15.2", "compression": "^1.7.4", "cors": "^2.8.5", "express": "^4.17.1", @@ -44,7 +45,6 @@ "@types/http-errors": "^1.6.3", "@types/morgan": "^1.9.0", "@types/supertest": "^2.0.8", - "@types/webpack-env": "^1.15.2", "@types/yaml": "^1.9.7", "get-port": "^5.1.1", "http-errors": "^1.7.3", diff --git a/packages/cli/config/tsconfig.json b/packages/cli/config/tsconfig.json index f6d622ee16..ce031bc5e7 100644 --- a/packages/cli/config/tsconfig.json +++ b/packages/cli/config/tsconfig.json @@ -32,6 +32,6 @@ "strictPropertyInitialization": true, "stripInternal": true, "target": "ES2019", - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index 6a15c8e35f..ce821a585b 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -15,16 +15,15 @@ */ import webpack from 'webpack'; -import { createConfig } from './config'; +import { createBackendConfig } from './config'; import { resolveBundlingPaths } from './paths'; import { ServeOptions } from './types'; export async function serveBackend(options: ServeOptions) { const paths = resolveBundlingPaths(options); - const config = createConfig(paths, { + const config = createBackendConfig(paths, { ...options, isDev: true, - isBackend: true, }); const compiler = webpack(config); diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index e5343d3ccc..1193ed505e 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -40,7 +40,6 @@ export async function buildBundle(options: BuildOptions) { ...options, checksEnabled: false, isDev: false, - isBackend: false, baseUrl: resolveBaseUrl(options.config), }); const compiler = webpack(config); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 23098318ec..e6d47573ef 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -24,7 +24,7 @@ import { optimization } from './optimization'; import { Config } from '@backstage/config'; import { BundlingPaths } from './paths'; import { transforms } from './transforms'; -import { BundlingOptions } from './types'; +import { BundlingOptions, BackendBundlingOptions } from './types'; // import checkRequiredFiles from 'react-dev-utils/checkRequiredFiles'; // import ModuleNotFoundPlugin from 'react-dev-utils/ModuleNotFoundPlugin'; // import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware'; @@ -47,7 +47,7 @@ export function createConfig( paths: BundlingPaths, options: BundlingOptions, ): webpack.Configuration { - const { checksEnabled, isDev, isBackend } = options; + const { checksEnabled, isDev } = options; const { plugins, loaders } = transforms(options); @@ -92,7 +92,66 @@ export function createConfig( }), ); - const backendRelatedConfig = { + return { + mode: isDev ? 'development' : 'production', + profile: false, + node: { + module: 'empty', + dgram: 'empty', + dns: 'mock', + fs: 'empty', + http2: 'empty', + net: 'empty', + tls: 'empty', + child_process: 'empty', + }, + optimization: optimization(options), + bail: false, + performance: { + hints: false, // we check the gzip size instead + }, + devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map', + context: paths.targetPath, + entry: [require.resolve('react-hot-loader/patch'), paths.targetEntry], + resolve: { + extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], + mainFields: ['main:src', 'browser', 'module', 'main'], + plugins: [ + new ModuleScopePlugin( + [paths.targetSrc, paths.targetDev], + [paths.targetPackageJson], + ), + ], + alias: { + 'react-dom': '@hot-loader/react-dom', + }, + }, + module: { + rules: loaders, + }, + output: { + path: paths.targetDist, + publicPath: validBaseUrl.pathname, + filename: isDev ? '[name].js' : '[name].[hash:8].js', + chunkFilename: isDev + ? '[name].chunk.js' + : '[name].[chunkhash:8].chunk.js', + }, + plugins, + }; +} + +export function createBackendConfig( + paths: BundlingPaths, + options: BackendBundlingOptions, +): webpack.Configuration { + const { checksEnabled, isDev } = options; + + const { loaders } = transforms(options); + + return { + mode: isDev ? 'development' : 'production', + profile: false, ...(isDev ? { watch: true, @@ -117,44 +176,17 @@ export function createConfig( __filename: true, global: true, }, - }; - - return { - mode: isDev ? 'development' : 'production', - profile: false, - ...(isBackend - ? backendRelatedConfig - : { - node: { - module: 'empty', - dgram: 'empty', - dns: 'mock', - fs: 'empty', - http2: 'empty', - net: 'empty', - tls: 'empty', - child_process: 'empty', - }, - optimization: optimization(options), - }), bail: false, performance: { hints: false, // we check the gzip size instead }, devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map', context: paths.targetPath, - entry: [ - ...(isBackend - ? ['webpack/hot/poll?100'] - : [require.resolve('react-hot-loader/patch')]), - paths.targetEntry, - ], + entry: ['webpack/hot/poll?100', paths.targetEntry], resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['main:src', 'browser', 'module', 'main'], - ...(isBackend - ? { modules: [paths.targetNodeModules, paths.rootNodeModules] } - : {}), + modules: [paths.targetNodeModules, paths.rootNodeModules], plugins: [ new ModuleScopePlugin( [paths.targetSrc, paths.targetDev], @@ -170,17 +202,29 @@ export function createConfig( }, output: { path: paths.targetDist, - publicPath: validBaseUrl.pathname, filename: isDev ? '[name].js' : '[name].[hash:8].js', chunkFilename: isDev ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js', }, - plugins: isBackend - ? [ - new StartServerPlugin('main.js'), - new webpack.HotModuleReplacementPlugin(), - ] - : plugins, + plugins: [ + new StartServerPlugin('main.js'), + new webpack.HotModuleReplacementPlugin(), + ...(checksEnabled + ? [ + new ForkTsCheckerWebpackPlugin({ + tsconfig: paths.targetTsConfig, + eslint: true, + eslintOptions: { + parserOptions: { + project: paths.targetTsConfig, + tsconfigRootDir: paths.targetPath, + }, + }, + reportFiles: ['**', '!**/__tests__/**', '!**/?(*.)(spec|test).*'], + }), + ] + : []), + ], }; } diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index ddc6ee88fa..c7bacc0c7d 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -33,7 +33,6 @@ export async function serveBundle(options: ServeOptions) { const config = createConfig(paths, { ...options, isDev: true, - isBackend: false, baseUrl: url, }); const compiler = webpack(config); diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 98bcfe49ef..0cd800f2ea 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -16,14 +16,16 @@ import webpack, { Module, Plugin } from 'webpack'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import { BundlingOptions } from './types'; +import { BundlingOptions, BackendBundlingOptions } from './types'; type Transforms = { loaders: Module['rules']; plugins: Plugin[]; }; -export const transforms = (options: BundlingOptions): Transforms => { +export const transforms = ( + options: BundlingOptions | BackendBundlingOptions, +): Transforms => { const { isDev } = options; const loaders = [ diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 076faf8151..5d0ba66a51 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -22,10 +22,11 @@ export type BundlingOptions = { isDev: boolean; config: Config; appConfigs: AppConfig[]; - isBackend: boolean; baseUrl: URL; }; +export type BackendBundlingOptions = Omit; + export type ServeOptions = BundlingPathsOptions & { checksEnabled: boolean; config: Config; diff --git a/yarn.lock b/yarn.lock index 1a674f13dc..2afeb2eb37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2406,6 +2406,11 @@ dependencies: "@types/node" ">= 8" +"@open-draft/until@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" + integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q== + "@reach/router@^1.2.1": version "1.3.3" resolved "https://registry.npmjs.org/@reach/router/-/router-1.3.3.tgz#58162860dce6c9449d49be86b0561b5ef46d80db" @@ -3485,6 +3490,11 @@ dependencies: "@types/express" "*" +"@types/cookie@^0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" + integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== + "@types/cookiejar@*": version "2.1.1" resolved "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" @@ -6665,6 +6675,11 @@ cookie@0.4.0: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + cookiejar@^2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -9774,6 +9789,11 @@ graphql@15.0.0: resolved "https://registry.npmjs.org/graphql/-/graphql-15.0.0.tgz#042a5eb5e2506a2e2111ce41eb446a8e570b8be9" integrity sha512-ZyVO1xIF9F+4cxfkdhOJINM+51B06Friuv4M66W7HzUOeFd+vNzUn4vtswYINPi6sysjf1M2Ri/rwZALqgwbaQ== +graphql@^15.0.0: + version "15.1.0" + resolved "https://registry.npmjs.org/graphql/-/graphql-15.1.0.tgz#b93e28de805294ec08e1630d901db550cb8960a1" + integrity sha512-0TVyfOlCGhv/DBczQkJmwXOK6fjWkjzY3Pt7wY8i0gcYXq8aogG3weCsg48m72lywKSeOqedEHvVPOvZvSD51Q== + growly@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -9938,6 +9958,11 @@ he@^1.2.0: resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +headers-utils@^1.1.9, headers-utils@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/headers-utils/-/headers-utils-1.2.0.tgz#5e10d1bc9d2bccf789547afca5b991a3167241e8" + integrity sha512-4/BMXcWrJErw7JpM87gF8MNEXcIMLzepYZjNRv/P9ctgupl2Ywa3u1PgHtNhSRq84bHH9Ndlkdy7bSi+bZ9I9A== + helmet-crossdomain@0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e" @@ -13169,6 +13194,22 @@ ms@^2.0.0, ms@^2.1.1: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +msw@^0.19.0: + version "0.19.3" + resolved "https://registry.npmjs.org/msw/-/msw-0.19.3.tgz#88f39edbd37313bff15a0e7cd00c71406cbdbbae" + integrity sha512-HYLnyrCDDPP72GG/CeHPhBjHsZFYkz36rJLXDWccZWNA24gYjgrcp9iVqqitk2cI6NAJwsupRml9GkfpJBB74w== + dependencies: + "@open-draft/until" "^1.0.0" + "@types/cookie" "^0.3.3" + chalk "^4.0.0" + cookie "^0.4.1" + graphql "^15.0.0" + headers-utils "^1.1.9" + node-match-path "^0.4.2" + node-request-interceptor "^0.2.5" + statuses "^2.0.0" + yargs "^15.3.1" + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -13376,6 +13417,11 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" +node-match-path@^0.4.2: + version "0.4.2" + resolved "https://registry.npmjs.org/node-match-path/-/node-match-path-0.4.2.tgz#30cc39510fa493bff03c3d0d2fff711c868ec457" + integrity sha512-wfde4FOC5A8RTSUVZ7pTpBV+dJsr2vVxT6374VrNam6wnnhx6EvwAwL/E/r3AW/YU6XkeZggF5xfBlu4a/ULBg== + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -13416,6 +13462,14 @@ node-releases@^1.1.29, node-releases@^1.1.52: dependencies: semver "^6.3.0" +node-request-interceptor@^0.2.5: + version "0.2.6" + resolved "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.2.6.tgz#541278d7033bb6a8befb5dd793f83428cf6446a2" + integrity sha512-aJW1tPSM7nzuZFRe+C/KSz22GJO3CVFMxHHmMGX8Z+tjP7TCIVbzeckLFVfJG68BdVgrdOOP7Ejc57ag820eyA== + dependencies: + debug "^4.1.1" + headers-utils "^1.2.0" + nodemon@^2.0.2: version "2.0.4" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" @@ -17294,6 +17348,11 @@ static-extend@^0.1.1: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +statuses@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.0.tgz#aa7b107e018eb33e08e8aee2e7337e762dda1028" + integrity sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA== + stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"