From d2e25082df25c1c4132564f4cc2eb2fdda2017ae Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 10 Jun 2020 21:49:55 +0200 Subject: [PATCH 01/12] feat(cli): backend webpack serve --- packages/backend/package.json | 6 +- packages/cli/package.json | 4 ++ packages/cli/src/commands/backend/dev.ts | 32 +++++++++ packages/cli/src/index.ts | 6 ++ packages/cli/src/lib/bundler/backend.ts | 59 +++++++++++++++++ packages/cli/src/lib/bundler/config.ts | 79 +++++++++++++++++----- packages/cli/src/lib/bundler/index.ts | 1 + packages/cli/src/lib/bundler/paths.ts | 2 + packages/cli/src/lib/bundler/types.ts | 1 + yarn.lock | 83 +++++++----------------- 10 files changed, 194 insertions(+), 79 deletions(-) create mode 100644 packages/cli/src/commands/backend/dev.ts create mode 100644 packages/cli/src/lib/bundler/backend.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index 4e2610380c..98607b5a00 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,7 +1,7 @@ { "name": "example-backend", "version": "0.1.1-alpha.7", - "main": "dist", + "main": "dist/index.cjs", "types": "src/index.ts", "private": true, "license": "Apache-2.0", @@ -9,8 +9,8 @@ "node": ">=12" }, "scripts": { - "build": "tsc", - "start": "backstage-cli watch-deps --build -- tsc-watch --onFirstSuccess \\\"nodemon -r esm\\\"", + "build": "backstage-cli build --outputs cjs", + "start": "backstage-cli watch-deps --build -- backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", "clean": "backstage-cli clean", diff --git a/packages/cli/package.json b/packages/cli/package.json index 58b6c3fd84..0dbf9c2f71 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,6 +39,8 @@ "@rollup/plugin-node-resolve": "^7.1.1", "@spotify/eslint-config": "^7.0.1", "@sucrase/webpack-loader": "^2.0.0", + "@types/start-server-webpack-plugin": "^2.2.0", + "@types/webpack-node-externals": "^1.7.1", "bfj": "^7.0.2", "chalk": "^4.0.0", "chokidar": "^3.3.1", @@ -72,6 +74,7 @@ "rollup-plugin-peer-deps-external": "^2.2.2", "rollup-plugin-postcss": "^3.1.1", "rollup-plugin-typescript2": "^0.26.0", + "start-server-webpack-plugin": "^2.2.5", "style-loader": "^1.2.1", "sucrase": "^3.14.1", "tar": "^6.0.1", @@ -81,6 +84,7 @@ "url-loader": "^4.1.0", "webpack": "^4.41.6", "webpack-dev-server": "^3.10.3", + "webpack-node-externals": "^1.7.2", "yaml": "^1.10.0", "yml-loader": "^2.1.0", "yn": "^4.0.0" diff --git a/packages/cli/src/commands/backend/dev.ts b/packages/cli/src/commands/backend/dev.ts new file mode 100644 index 0000000000..f04f904e09 --- /dev/null +++ b/packages/cli/src/commands/backend/dev.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { loadConfig } from '@backstage/config-loader'; +import { Command } from 'commander'; +import { serveBackend } from '../../lib/bundler/backend'; + +export default async (cmd: Command) => { + const appConfigs = await loadConfig(); + const waitForExit = await serveBackend({ + entry: 'src/index', + checksEnabled: cmd.check, + config: ConfigReader.fromConfigs(appConfigs), + appConfigs, + }); + + await waitForExit(); +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index a0302c4713..ea71dc6485 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -41,6 +41,12 @@ const main = (argv: string[]) => { .option('--check', 'Enable type checking and linting') .action(lazyAction(() => import('./commands/app/serve'), 'default')); + program + .command('backend:dev') + .description('Start local development server with HMR for the backend') + .option('--check', 'Enable type checking and linting') + .action(lazyAction(() => import('./commands/backend/dev'), 'default')); + program .command('app:diff') .option('--check', 'Fail if changes are required') diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts new file mode 100644 index 0000000000..81ff6b6cff --- /dev/null +++ b/packages/cli/src/lib/bundler/backend.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import webpack from 'webpack'; +import { createConfig } from './config'; +import { resolveBundlingPaths } from './paths'; +import { ServeOptions } from './types'; + +export async function serveBackend(options: ServeOptions) { + const paths = resolveBundlingPaths(options); + const config = createConfig(paths, { + ...options, + isDev: true, + isBackend: true, + }); + + const compiler = webpack(config); + + const watcher = compiler.watch( + { + poll: true, + }, + (err: Error, _stats: any) => { + console.log('Build succeeded'); + if (err) { + console.error(err); + } + }, + ); + + const waitForExit = async () => { + for (const signal of ['SIGINT', 'SIGTERM'] as const) { + process.on(signal, () => { + // server.close(); + watcher.close(() => console.log('Watcher closed')); + // exit instead of resolve. The process is shutting down and resolving a promise here logs an error + process.exit(); + }); + } + + // Block indefinitely and wait for the interrupt signal + return new Promise(() => {}); + }; + + return waitForExit; +} diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index d46308f043..608f2d7b91 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -14,13 +14,15 @@ * limitations under the License. */ -import webpack from 'webpack'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; +import StartServerPlugin from 'start-server-webpack-plugin'; +import webpack from 'webpack'; +import nodeExternals from 'webpack-node-externals'; +import { optimization } from './optimization'; import { BundlingPaths } from './paths'; import { transforms } from './transforms'; -import { optimization } from './optimization'; import { BundlingOptions } from './types'; // import checkRequiredFiles from 'react-dev-utils/checkRequiredFiles'; // import ModuleNotFoundPlugin from 'react-dev-utils/ModuleNotFoundPlugin'; @@ -32,7 +34,7 @@ export function createConfig( paths: BundlingPaths, options: BundlingOptions, ): webpack.Configuration { - const { checksEnabled, isDev } = options; + const { checksEnabled, isDev, isBackend } = options; const { plugins, loaders } = transforms(options); @@ -80,16 +82,65 @@ export function createConfig( return { mode: isDev ? 'development' : 'production', profile: false, + ...(isBackend + ? { + watch: true, + watchOptions: { + ignored: [/node_modules\/(?!\@backstage)/], + // poll: 1000 + }, + externals: [ + nodeExternals({ + modulesDir: paths.rootNodeModules, + whitelist: [ + 'webpack/hot/poll?100', + /\@backstage\/.*\/(?!node_modules)/, + ], + }), + nodeExternals({ + modulesDir: paths.targetNodeModules, + whitelist: [ + 'webpack/hot/poll?100', + /\@backstage\/.*\/(?!node_modules)/, + ], + }), + ], + target: 'node', + node: { + __dirname: true, + __filename: true, + global: true, + }, + } + : { + 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], + entry: [ + ...(isBackend + ? ['webpack/hot/poll?100'] + : [require.resolve('react-hot-loader/patch')]), + paths.targetEntry, + ], resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['main:src', 'browser', 'module', 'main'], + modules: [paths.targetNodeModules, paths.rootNodeModules], plugins: [ new ModuleScopePlugin( [paths.targetSrc, paths.targetDev], @@ -111,17 +162,11 @@ export function createConfig( ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js', }, - optimization: optimization(options), - plugins, - node: { - module: 'empty', - dgram: 'empty', - dns: 'mock', - fs: 'empty', - http2: 'empty', - net: 'empty', - tls: 'empty', - child_process: 'empty', - }, + plugins: isBackend + ? [ + new StartServerPlugin('main.js'), + new webpack.HotModuleReplacementPlugin(), + ] + : plugins, }; } diff --git a/packages/cli/src/lib/bundler/index.ts b/packages/cli/src/lib/bundler/index.ts index cdfb5f3897..2030b4bb96 100644 --- a/packages/cli/src/lib/bundler/index.ts +++ b/packages/cli/src/lib/bundler/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ +export { serveBackend } from './backend'; export { buildBundle } from './bundle'; export { serveBundle } from './server'; diff --git a/packages/cli/src/lib/bundler/paths.ts b/packages/cli/src/lib/bundler/paths.ts index cec270178a..1e1cd1298a 100644 --- a/packages/cli/src/lib/bundler/paths.ts +++ b/packages/cli/src/lib/bundler/paths.ts @@ -60,6 +60,8 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetTsConfig: paths.resolveTargetRoot('tsconfig.json'), targetNodeModules: paths.resolveTarget('node_modules'), targetPackageJson: paths.resolveTarget('package.json'), + rootNodeModules: paths.resolveTargetRoot('node_modules'), + root: paths.targetRoot, }; } diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 332a105182..b375897fc9 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -22,6 +22,7 @@ export type BundlingOptions = { isDev: boolean; config: Config; appConfigs: AppConfig[]; + isBackend?: boolean; }; export type ServeOptions = BundlingPathsOptions & { diff --git a/yarn.lock b/yarn.lock index c75690a1fd..107ba84663 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2406,11 +2406,6 @@ 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" @@ -3481,11 +3476,6 @@ 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" @@ -4028,6 +4018,13 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/start-server-webpack-plugin@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@types/start-server-webpack-plugin/-/start-server-webpack-plugin-2.2.0.tgz#a7c4595c715eda083d92ca1ea184d97db3d8fc7b" + integrity sha512-TFiZWMPuiMR/utvjk6ENi0HPtQl38HnPMYfJqm04ztpzITHzTCXt7T7LyXnP9eTwg4lLQkmRUaFy04iEyjoJmw== + dependencies: + "@types/webpack" "*" + "@types/styled-jsx@^2.2.8": version "2.2.8" resolved "https://registry.npmjs.org/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234" @@ -4151,6 +4148,13 @@ resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.15.1.tgz#c8e84705e08eed430b5e15b39c65b0944e4d1422" integrity sha512-eWN5ElDTeBc5lRDh95SqA8x18D0ll2pWudU3uWiyfsRmIZcmUXpEsxPU+7+BsdCrO2vfLRC629u/MmjbmF+2tA== +"@types/webpack-node-externals@^1.7.1": + version "1.7.1" + resolved "https://registry.npmjs.org/@types/webpack-node-externals/-/webpack-node-externals-1.7.1.tgz#73d0d7ae0e98cfbd69b7443388302cd69217494a" + integrity sha512-kbO2gYPKvMb5j1KOgnIuUH52CKul9Ud4b10J5n+JX8oHmgu86hYpBVfrV4bMDe5lhCaO64h8QrKz7WnRZzqkbA== + dependencies: + "@types/webpack" "*" + "@types/webpack-sources@*": version "0.1.6" resolved "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.6.tgz#3d21dfc2ec0ad0c77758e79362426a9ba7d7cbcb" @@ -6657,11 +6661,6 @@ 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" @@ -9771,11 +9770,6 @@ 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" @@ -9940,11 +9934,6 @@ 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.3, headers-utils@^1.1.9: - 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,22 +13158,6 @@ 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.0" - resolved "https://registry.npmjs.org/msw/-/msw-0.19.0.tgz#fd37015787d40db82d243a2853be66c466675e72" - integrity sha512-1TpmJzJ+afBWTRNJYoeW8KwLQbCVlvvhw2u/eRuIYfel+bPqcut5NaSgo+Bi4C0Q/7M5wza00w1GEuOXQu6FCA== - 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.4" - 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" @@ -13399,11 +13372,6 @@ 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" @@ -13444,14 +13412,6 @@ node-releases@^1.1.29, node-releases@^1.1.52: dependencies: semver "^6.3.0" -node-request-interceptor@^0.2.4: - version "0.2.4" - resolved "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.2.4.tgz#f03a1b874823d0bea311a14280227707be946298" - integrity sha512-/htjDLmygBczT5qYPaSxfAEtMkc0LGuH6jqAP1o+TKfQh6yQfFyTtac25cpY8+pb4EawHljCLUN7dCeed9SdPA== - dependencies: - debug "^4.1.1" - headers-utils "^1.1.3" - nodemon@^2.0.2: version "2.0.4" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" @@ -17296,6 +17256,11 @@ start-server-and-test@^1.10.11: ps-tree "1.2.0" wait-on "4.0.0" +start-server-webpack-plugin@^2.2.5: + version "2.2.5" + resolved "https://registry.npmjs.org/start-server-webpack-plugin/-/start-server-webpack-plugin-2.2.5.tgz#4a2838759b0f36acd11b0b2f5f196f289ae29d31" + integrity sha512-DRCkciwCJoCFZ+wt3wWMkR1M2mpVhJbUKFXqhK3FWyIUKYb42NnocH5sMwqgo+nPNHupqNwK/v8lgfBbr2NKdg== + state-toggle@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" @@ -17314,11 +17279,6 @@ 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" @@ -19057,6 +19017,11 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" +webpack-node-externals@^1.7.2: + version "1.7.2" + resolved "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3" + integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg== + webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" From 813c8777eb689cf1a913c664e69f0c79ea53e4db Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 10 Jun 2020 21:50:29 +0200 Subject: [PATCH 02/12] fix(cli): prettier config --- package.json | 1 - prettier.config.js | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 prettier.config.js diff --git a/package.json b/package.json index 437ce36c4b..fd9e42ec65 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "pre-commit": "lint-staged" } }, - "prettier": "@spotify/prettier-config", "lint-staged": { "*.{js,jsx,ts,tsx}": [ "eslint --fix", diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000000..ed2aaa1774 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,19 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For some reason VSCode's extension doesn't work with field in the +// package.json pointing to the same package +module.exports = require('@spotify/prettier-config'); From 96c295b0e1c383c7c75c32b9ae109948b26af933 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 10 Jun 2020 22:00:55 +0200 Subject: [PATCH 03/12] fix(cli): lint --- packages/cli/src/lib/bundler/backend.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index 81ff6b6cff..e6d2ff3428 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -33,7 +33,7 @@ export async function serveBackend(options: ServeOptions) { { poll: true, }, - (err: Error, _stats: any) => { + (err: Error) => { console.log('Build succeeded'); if (err) { console.error(err); @@ -44,8 +44,7 @@ export async function serveBackend(options: ServeOptions) { const waitForExit = async () => { for (const signal of ['SIGINT', 'SIGTERM'] as const) { process.on(signal, () => { - // server.close(); - watcher.close(() => console.log('Watcher closed')); + watcher.close(() => console.log('Stopped watcher')); // exit instead of resolve. The process is shutting down and resolving a promise here logs an error process.exit(); }); From 0331d33a37721b45cdd5f2408da78c7ee4f05a76 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 10 Jun 2020 23:29:26 +0200 Subject: [PATCH 04/12] fix(cli): remove modules from webpack config --- packages/cli/src/lib/bundler/backend.ts | 3 +- packages/cli/src/lib/bundler/bundle.ts | 1 + packages/cli/src/lib/bundler/config.ts | 60 ++++++++++++------------- packages/cli/src/lib/bundler/server.ts | 6 ++- packages/cli/src/lib/bundler/types.ts | 2 +- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index e6d2ff3428..6a15c8e35f 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -34,10 +34,9 @@ export async function serveBackend(options: ServeOptions) { poll: true, }, (err: Error) => { - console.log('Build succeeded'); if (err) { console.error(err); - } + } else console.log('Build succeeded'); }, ); diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index ad1a63ebaf..a088202fa8 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -40,6 +40,7 @@ export async function buildBundle(options: BuildOptions) { ...options, checksEnabled: false, isDev: false, + isBackend: false, }); const compiler = webpack(config); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 608f2d7b91..241ef6a9af 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -79,39 +79,40 @@ export function createConfig( }), ); + const backendRelatedConfig = { + watch: true, + watchOptions: { + ignored: [/node_modules\/(?!\@backstage)/], + }, + externals: [ + nodeExternals({ + modulesDir: paths.rootNodeModules, + whitelist: [ + 'webpack/hot/poll?100', + /\@backstage\/.*\/(?!node_modules)/, + ], + }), + nodeExternals({ + modulesDir: paths.targetNodeModules, + whitelist: [ + 'webpack/hot/poll?100', + /\@backstage\/.*\/(?!node_modules)/, + ], + }), + ], + target: 'node' as const, + node: { + __dirname: true, + __filename: true, + global: true, + }, + }; + return { mode: isDev ? 'development' : 'production', profile: false, ...(isBackend - ? { - watch: true, - watchOptions: { - ignored: [/node_modules\/(?!\@backstage)/], - // poll: 1000 - }, - externals: [ - nodeExternals({ - modulesDir: paths.rootNodeModules, - whitelist: [ - 'webpack/hot/poll?100', - /\@backstage\/.*\/(?!node_modules)/, - ], - }), - nodeExternals({ - modulesDir: paths.targetNodeModules, - whitelist: [ - 'webpack/hot/poll?100', - /\@backstage\/.*\/(?!node_modules)/, - ], - }), - ], - target: 'node', - node: { - __dirname: true, - __filename: true, - global: true, - }, - } + ? backendRelatedConfig : { node: { module: 'empty', @@ -140,7 +141,6 @@ export function createConfig( resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['main:src', 'browser', 'module', 'main'], - modules: [paths.targetNodeModules, paths.rootNodeModules], plugins: [ new ModuleScopePlugin( [paths.targetSrc, paths.targetDev], diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index bf78c9b9fb..a004bee1a9 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -38,7 +38,11 @@ export async function serveBundle(options: ServeOptions) { const paths = resolveBundlingPaths(options); const pkgPath = paths.targetPackageJson; const pkg = await fs.readJson(pkgPath); - const config = createConfig(paths, { ...options, isDev: true }); + const config = createConfig(paths, { + ...options, + isDev: true, + isBackend: false, + }); const compiler = webpack(config); const server = new WebpackDevServer(compiler, { diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index b375897fc9..62737374bd 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -22,7 +22,7 @@ export type BundlingOptions = { isDev: boolean; config: Config; appConfigs: AppConfig[]; - isBackend?: boolean; + isBackend: boolean; }; export type ServeOptions = BundlingPathsOptions & { From a1a60ad9d1563d36483d2b293eb53fcfc49f17de Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Thu, 11 Jun 2020 02:51:06 +0200 Subject: [PATCH 05/12] feat: hmr logic for the backend --- packages/backend-common/package.json | 3 ++ packages/backend-common/src/hot.ts | 51 +++++++++++++++++++ packages/backend-common/src/index.ts | 1 + .../src/service/ServiceBuilderImpl.ts | 26 ++++++++-- .../src/service/createServiceBuilder.ts | 4 +- packages/backend-common/tsconfig.json | 2 +- packages/backend/src/index.ts | 23 ++++++--- packages/backend/src/plugins/catalog.ts | 5 +- packages/backend/tsconfig.json | 2 +- packages/cli/src/lib/bundler/config.ts | 13 ++--- plugins/auth-backend/tsconfig.json | 2 +- .../src/service/standaloneServer.ts | 4 +- plugins/catalog-backend/tsconfig.json | 2 +- plugins/identity-backend/tsconfig.json | 2 +- plugins/sentry-backend/tsconfig.json | 2 +- yarn.lock | 17 +++++++ 16 files changed, 131 insertions(+), 28 deletions(-) create mode 100644 packages/backend-common/src/hot.ts diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 54202975c3..b7d5cf7c11 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -27,11 +27,13 @@ "clean": "backstage-cli clean" }, "dependencies": { + "@types/stoppable": "^1.1.0", "compression": "^1.7.4", "cors": "^2.8.5", "express": "^4.17.1", "helmet": "^3.22.0", "morgan": "^1.10.0", + "stoppable": "^1.1.0", "winston": "^3.2.1" }, "devDependencies": { @@ -42,6 +44,7 @@ "@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/backend-common/src/hot.ts b/packages/backend-common/src/hot.ts new file mode 100644 index 0000000000..3043bcb681 --- /dev/null +++ b/packages/backend-common/src/hot.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export function useHotEffect( + _module: NodeModule, + effectFactory: () => () => void, +) { + const cancelEffect = effectFactory(); + if (_module.hot) { + _module.hot.addDisposeHandler(() => { + cancelEffect(); + }); + } +} + +export function useHotMemoize( + _module: NodeModule, + valueFactory: () => T, +): T { + if (!_module.hot) { + return valueFactory(); + } + const index = (useHotMemoize as any).index ?? 0; + (useHotMemoize as any).index += 1; + const prevValue = _module.hot?.data?.[index]; + if (prevValue) { + _module.hot!.addDisposeHandler(data => { + data[index] = prevValue; + }); + return prevValue; + } + const newValue = valueFactory(); + if (_module.hot) { + _module.hot.addDisposeHandler(data => { + data[index] = newValue; + }); + } + return newValue; +} diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index 11689aafff..0e4e5b2c6b 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -18,3 +18,4 @@ export * from './errors'; export * from './logging'; export * from './middleware'; export * from './service'; +export * from './hot'; diff --git a/packages/backend-common/src/service/ServiceBuilderImpl.ts b/packages/backend-common/src/service/ServiceBuilderImpl.ts index ac35d52112..844990a39d 100644 --- a/packages/backend-common/src/service/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/ServiceBuilderImpl.ts @@ -19,6 +19,7 @@ import cors from 'cors'; import express, { Router } from 'express'; import helmet from 'helmet'; import { Server } from 'http'; +import stoppable from 'stoppable'; import { Logger } from 'winston'; import { getRootLogger } from '../logging'; import { @@ -27,6 +28,7 @@ import { requestLoggingHandler, } from '../middleware'; import { ServiceBuilder } from './types'; +import { useHotEffect } from '../hot'; const DEFAULT_PORT = 7000; @@ -35,9 +37,14 @@ export class ServiceBuilderImpl implements ServiceBuilder { private logger: Logger | undefined; private corsOptions: cors.CorsOptions | undefined; private routers: [string, Router][]; - - constructor() { + /** + * Reference to the module where builder is created + * Needed for the HMR + */ + private module: NodeModule; + constructor(module: NodeModule) { this.routers = []; + this.module = module; } setPort(port: number): ServiceBuilder { @@ -82,9 +89,20 @@ export class ServiceBuilderImpl implements ServiceBuilder { logger.error(`Failed to start up on port ${port}, ${e}`); reject(e); }); - const server = app.listen(port, () => { - logger.info(`Listening on port ${port}`); + const server = stoppable( + app.listen(port, () => { + logger.info(`Listening on port ${port}`); + }), + 0, + ); + + useHotEffect(this.module, () => { + return () => + server.stop((e: any) => { + if (e) console.error(e); + }); }); + resolve(server); }); } diff --git a/packages/backend-common/src/service/createServiceBuilder.ts b/packages/backend-common/src/service/createServiceBuilder.ts index ffd8901def..daef612fcf 100644 --- a/packages/backend-common/src/service/createServiceBuilder.ts +++ b/packages/backend-common/src/service/createServiceBuilder.ts @@ -19,6 +19,6 @@ import { ServiceBuilderImpl } from './ServiceBuilderImpl'; /** * Creates a new service builder. */ -export function createServiceBuilder() { - return new ServiceBuilderImpl(); +export function createServiceBuilder(_module: NodeModule) { + return new ServiceBuilderImpl(_module); } diff --git a/packages/backend-common/tsconfig.json b/packages/backend-common/tsconfig.json index ca39bf9964..2e645bef0b 100644 --- a/packages/backend-common/tsconfig.json +++ b/packages/backend-common/tsconfig.json @@ -9,6 +9,6 @@ "target": "ES2019", "module": "commonjs", "esModuleInterop": true, - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 0f0733a8ec..09e244545b 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -22,7 +22,11 @@ * Happy hacking! */ -import { createServiceBuilder, getRootLogger } from '@backstage/backend-common'; +import { + createServiceBuilder, + getRootLogger, + useHotMemoize, +} from '@backstage/backend-common'; import knex from 'knex'; import auth from './plugins/auth'; import catalog from './plugins/catalog'; @@ -45,19 +49,24 @@ function createEnv(plugin: string): PluginEnvironment { } async function main() { - const service = createServiceBuilder() + const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); + const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); + const authEnv = useHotMemoize(module, () => createEnv('auth')); + const identityEnv = useHotMemoize(module, () => createEnv('identity')); + + const service = createServiceBuilder(module) .enableCors({ origin: 'http://localhost:3000', credentials: true, }) - .addRouter('/catalog', await catalog(createEnv('catalog'))) - .addRouter('/scaffolder', await scaffolder(createEnv('scaffolder'))) + .addRouter('/catalog', await catalog(catalogEnv)) + .addRouter('/scaffolder', await scaffolder(scaffolderEnv)) .addRouter( '/sentry', await sentry(getRootLogger().child({ type: 'plugin', plugin: 'sentry' })), ) - .addRouter('/auth', await auth(createEnv('auth'))) - .addRouter('/identity', await identity(createEnv('identity'))); + .addRouter('/auth', await auth(authEnv)) + .addRouter('/identity', await identity(identityEnv)); await service.start().catch(err => { console.log(err); @@ -66,3 +75,5 @@ async function main() { } main(); + +module.hot?.accept(); diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend/src/plugins/catalog.ts index 8d8ac5b47b..a9e4fa8ce6 100644 --- a/packages/backend/src/plugins/catalog.ts +++ b/packages/backend/src/plugins/catalog.ts @@ -24,6 +24,7 @@ import { runPeriodically, } from '@backstage/plugin-catalog-backend'; import { PluginEnvironment } from '../types'; +import { useHotEffect } from '@backstage/backend-common'; export default async function createPlugin({ logger, @@ -41,7 +42,9 @@ export default async function createPlugin({ logger, ); - runPeriodically(() => higherOrderOperation.refreshAllLocations(), 10000); + useHotEffect(module, () => + runPeriodically(() => higherOrderOperation.refreshAllLocations(), 10000), + ); return await createRouter({ entitiesCatalog, diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 04701a5502..269b22607c 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -10,6 +10,6 @@ "module": "commonjs", "esModuleInterop": true, "lib": ["es2019", "dom"], - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 241ef6a9af..0b664f7cf3 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -87,17 +87,11 @@ export function createConfig( externals: [ nodeExternals({ modulesDir: paths.rootNodeModules, - whitelist: [ - 'webpack/hot/poll?100', - /\@backstage\/.*\/(?!node_modules)/, - ], + whitelist: ['webpack/hot/poll?100', /\@backstage\/.*/], }), nodeExternals({ modulesDir: paths.targetNodeModules, - whitelist: [ - 'webpack/hot/poll?100', - /\@backstage\/.*\/(?!node_modules)/, - ], + whitelist: ['webpack/hot/poll?100', /\@backstage\/.*/], }), ], target: 'node' as const, @@ -141,6 +135,9 @@ export function createConfig( resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['main:src', 'browser', 'module', 'main'], + ...(isBackend + ? { modules: [paths.targetNodeModules, paths.rootNodeModules] } + : {}), plugins: [ new ModuleScopePlugin( [paths.targetSrc, paths.targetDev], diff --git a/plugins/auth-backend/tsconfig.json b/plugins/auth-backend/tsconfig.json index 015a967f76..6f1acf8dce 100644 --- a/plugins/auth-backend/tsconfig.json +++ b/plugins/auth-backend/tsconfig.json @@ -10,6 +10,6 @@ "module": "commonjs", "esModuleInterop": true, "lib": ["es2019"], - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/plugins/catalog-backend/src/service/standaloneServer.ts b/plugins/catalog-backend/src/service/standaloneServer.ts index f19dfaf282..93c8b86779 100644 --- a/plugins/catalog-backend/src/service/standaloneServer.ts +++ b/plugins/catalog-backend/src/service/standaloneServer.ts @@ -54,7 +54,7 @@ export async function startStandaloneServer( higherOrderOperation, logger, }); - const service = createServiceBuilder() + const service = createServiceBuilder(module) .enableCors({ origin: 'http://localhost:3000' }) .addRouter('/catalog', router); return await service.start().catch(err => { @@ -62,3 +62,5 @@ export async function startStandaloneServer( process.exit(1); }); } + +module.hot?.accept(); diff --git a/plugins/catalog-backend/tsconfig.json b/plugins/catalog-backend/tsconfig.json index 015a967f76..6f1acf8dce 100644 --- a/plugins/catalog-backend/tsconfig.json +++ b/plugins/catalog-backend/tsconfig.json @@ -10,6 +10,6 @@ "module": "commonjs", "esModuleInterop": true, "lib": ["es2019"], - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/plugins/identity-backend/tsconfig.json b/plugins/identity-backend/tsconfig.json index 015a967f76..6f1acf8dce 100644 --- a/plugins/identity-backend/tsconfig.json +++ b/plugins/identity-backend/tsconfig.json @@ -10,6 +10,6 @@ "module": "commonjs", "esModuleInterop": true, "lib": ["es2019"], - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/plugins/sentry-backend/tsconfig.json b/plugins/sentry-backend/tsconfig.json index 015a967f76..6f1acf8dce 100644 --- a/plugins/sentry-backend/tsconfig.json +++ b/plugins/sentry-backend/tsconfig.json @@ -10,6 +10,6 @@ "module": "commonjs", "esModuleInterop": true, "lib": ["es2019"], - "types": ["node", "jest"] + "types": ["node", "jest", "webpack-env"] } } diff --git a/yarn.lock b/yarn.lock index 107ba84663..343d9ef3dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4025,6 +4025,13 @@ dependencies: "@types/webpack" "*" +"@types/stoppable@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@types/stoppable/-/stoppable-1.1.0.tgz#a5fa6a48120b109ca9233eed05c67c50bc4f3b91" + integrity sha512-BRR23Q9CJduH7AM6mk4JRttd8XyFkb4qIPZu4mdLF+VoP+wcjIxIWIKiBbN78NBbEuynrAyMPtzOHnIp2B/JPQ== + dependencies: + "@types/node" "*" + "@types/styled-jsx@^2.2.8": version "2.2.8" resolved "https://registry.npmjs.org/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234" @@ -4148,6 +4155,11 @@ resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.15.1.tgz#c8e84705e08eed430b5e15b39c65b0944e4d1422" integrity sha512-eWN5ElDTeBc5lRDh95SqA8x18D0ll2pWudU3uWiyfsRmIZcmUXpEsxPU+7+BsdCrO2vfLRC629u/MmjbmF+2tA== +"@types/webpack-env@^1.15.2": + version "1.15.2" + resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a" + integrity sha512-67ZgZpAlhIICIdfQrB5fnDvaKFcDxpKibxznfYRVAT4mQE41Dido/3Ty+E3xGBmTogc5+0Qb8tWhna+5B8z1iQ== + "@types/webpack-node-externals@^1.7.1": version "1.7.1" resolved "https://registry.npmjs.org/@types/webpack-node-externals/-/webpack-node-externals-1.7.1.tgz#73d0d7ae0e98cfbd69b7443388302cd69217494a" @@ -17284,6 +17296,11 @@ stealthy-require@^1.1.1: resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +stoppable@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" + integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== + store2@^2.7.1: version "2.10.0" resolved "https://registry.npmjs.org/store2/-/store2-2.10.0.tgz#46b82bb91878daf1b0d56dec2f1d41e54d5103cf" From d85e78bd2b36c196203b98db01c8a08aa845bcd0 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Thu, 11 Jun 2020 14:29:15 +0200 Subject: [PATCH 06/12] fix(cli): adjusted build and main field for backend --- packages/backend/package.json | 6 +++--- packages/cli/src/lib/bundler/config.ts | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 98607b5a00..3a97ab71ee 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,7 +1,7 @@ { "name": "example-backend", "version": "0.1.1-alpha.7", - "main": "dist/index.cjs", + "main": "dist", "types": "src/index.ts", "private": true, "license": "Apache-2.0", @@ -9,8 +9,8 @@ "node": ">=12" }, "scripts": { - "build": "backstage-cli build --outputs cjs", - "start": "backstage-cli watch-deps --build -- backstage-cli backend:dev", + "build": "tsc", + "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", "clean": "backstage-cli clean", diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 241ef6a9af..0915ba73d2 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -80,10 +80,14 @@ export function createConfig( ); const backendRelatedConfig = { - watch: true, - watchOptions: { - ignored: [/node_modules\/(?!\@backstage)/], - }, + ...(isDev + ? { + watch: true, + watchOptions: { + ignored: [/node_modules\/(?!\@backstage)/], + }, + } + : {}), externals: [ nodeExternals({ modulesDir: paths.rootNodeModules, From 626b1acb41d91483587e4ef52c42cfcca6d73e9a Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Mon, 15 Jun 2020 21:10:59 +0200 Subject: [PATCH 07/12] chore: revert prettier config for now --- package.json | 1 + prettier.config.js | 19 ------------------- 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 prettier.config.js diff --git a/package.json b/package.json index fd9e42ec65..437ce36c4b 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "pre-commit": "lint-staged" } }, + "prettier": "@spotify/prettier-config", "lint-staged": { "*.{js,jsx,ts,tsx}": [ "eslint --fix", diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index ed2aaa1774..0000000000 --- a/prettier.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// For some reason VSCode's extension doesn't work with field in the -// package.json pointing to the same package -module.exports = require('@spotify/prettier-config'); From 9fe15e6726b37b1fcec68e5c5559f98d48f5e45e Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Mon, 15 Jun 2020 22:34:53 +0200 Subject: [PATCH 08/12] feat: point all backend to src --- packages/backend-common/package.json | 2 +- plugins/auth-backend/package.json | 2 +- plugins/catalog-backend/package.json | 2 +- plugins/identity-backend/package.json | 2 +- plugins/scaffolder-backend/package.json | 2 +- plugins/sentry-backend/package.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 97e9626b22..1a78039efd 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -2,7 +2,7 @@ "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "private": false, "publishConfig": { diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 9ee11eca52..5eff22126d 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index d98afbe4d3..9abfb1646a 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, diff --git a/plugins/identity-backend/package.json b/plugins/identity-backend/package.json index 0d1f6b99e5..ae7526daa2 100644 --- a/plugins/identity-backend/package.json +++ b/plugins/identity-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-identity-backend", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 1d7e3d4388..da87c707aa 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, diff --git a/plugins/sentry-backend/package.json b/plugins/sentry-backend/package.json index fd9638afe3..03846ea5a9 100644 --- a/plugins/sentry-backend/package.json +++ b/plugins/sentry-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry-backend", "version": "0.1.1-alpha.8", - "main": "dist", + "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, From 417a4d538e57f02ae7f8070bf923fdba9a2e3bbc Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Mon, 15 Jun 2020 22:36:36 +0200 Subject: [PATCH 09/12] feat: more clean hot hookz --- packages/backend-common/src/hot.ts | 73 +++++++++++++++---- .../src/service/ServiceBuilderImpl.ts | 13 ++-- packages/backend/src/plugins/catalog.ts | 5 +- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/packages/backend-common/src/hot.ts b/packages/backend-common/src/hot.ts index 3043bcb681..f684b5cba1 100644 --- a/packages/backend-common/src/hot.ts +++ b/packages/backend-common/src/hot.ts @@ -13,11 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export function useHotEffect( - _module: NodeModule, - effectFactory: () => () => void, -) { - const cancelEffect = effectFactory(); + +/** + * This function allows devs to cleanup + * ongoing effects when module gets hot-reloaded + * Useful for cleaning intervals, timers, requests etc + * @example + * ```ts + * const intervalId = setInterval(doStuff, 1000); + * useHotCleanup(module, () => clearInterval(intervalId)); + * ``` + * @param _module Reference to the current module where you invoke the fn + * @param cancelEffect Fn that cleans up the ongoing effects + */ +export function useHotCleanup(_module: NodeModule, cancelEffect: () => void) { if (_module.hot) { _module.hot.addDisposeHandler(() => { cancelEffect(); @@ -25,27 +34,59 @@ export function useHotEffect( } } +/** + * This function allows devs to preserve + * some value between hot-reloads. + * Useful for stateful parts of the backend + * @example + * ```ts + * const db = useHotMemoize(module, () => createDB(dbParams)); + * ``` + * @param _module Reference to the current module where you invoke the fn + * @param valueFactory Fn that returns the value you want to memoize + * @warning Don't use inside conditionals or loops, + * same rules as for hooks apply (https://reactjs.org/docs/hooks-rules.html) + */ export function useHotMemoize( _module: NodeModule, valueFactory: () => T, ): T { + const CURRENT_HOT_MEMOIZE_INDEX_KEY = 'backstage.io/hmr-memoize-key'; + if (!_module.hot) { + // Just return value straight away return valueFactory(); } - const index = (useHotMemoize as any).index ?? 0; - (useHotMemoize as any).index += 1; - const prevValue = _module.hot?.data?.[index]; + + if (_module.hot && typeof _module.hot.data === 'undefined') { + // First run, init the module data + _module.hot.data = { + [CURRENT_HOT_MEMOIZE_INDEX_KEY]: 0, + }; + } + + // Let's store data per module based on the order of the code invocation + const index = _module.hot.data?.[CURRENT_HOT_MEMOIZE_INDEX_KEY]; + // Increasing the counter after each call + _module.hot.data[CURRENT_HOT_MEMOIZE_INDEX_KEY] += 1; + + const prevValue = _module.hot.data?.[index]; + const createDisposeHandler = (value: any) => (data: { + [key: number]: any; + [indexKey: string]: number; + }) => { + // Preserving the value through the HMR process + data[index] = value; + // Decreasing the counter after each handler + data[CURRENT_HOT_MEMOIZE_INDEX_KEY] = index - 1; + }; + if (prevValue) { - _module.hot!.addDisposeHandler(data => { - data[index] = prevValue; - }); + _module.hot!.addDisposeHandler(createDisposeHandler(prevValue)); return prevValue; } + const newValue = valueFactory(); - if (_module.hot) { - _module.hot.addDisposeHandler(data => { - data[index] = newValue; - }); - } + _module.hot.addDisposeHandler(createDisposeHandler(newValue)); return newValue; } diff --git a/packages/backend-common/src/service/ServiceBuilderImpl.ts b/packages/backend-common/src/service/ServiceBuilderImpl.ts index 844990a39d..931d29b841 100644 --- a/packages/backend-common/src/service/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/ServiceBuilderImpl.ts @@ -28,7 +28,7 @@ import { requestLoggingHandler, } from '../middleware'; import { ServiceBuilder } from './types'; -import { useHotEffect } from '../hot'; +import { useHotCleanup } from '../hot'; const DEFAULT_PORT = 7000; @@ -96,12 +96,11 @@ export class ServiceBuilderImpl implements ServiceBuilder { 0, ); - useHotEffect(this.module, () => { - return () => - server.stop((e: any) => { - if (e) console.error(e); - }); - }); + useHotCleanup(this.module, () => + server.stop((e: any) => { + if (e) console.error(e); + }), + ); resolve(server); }); diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend/src/plugins/catalog.ts index 6f82836a79..41e4226001 100644 --- a/packages/backend/src/plugins/catalog.ts +++ b/packages/backend/src/plugins/catalog.ts @@ -24,7 +24,7 @@ import { runPeriodically, } from '@backstage/plugin-catalog-backend'; import { PluginEnvironment } from '../types'; -import { useHotEffect } from '@backstage/backend-common'; +import { useHotCleanup } from '@backstage/backend-common'; export default async function createPlugin({ logger, @@ -42,7 +42,8 @@ export default async function createPlugin({ logger, ); - useHotEffect(module, () => + useHotCleanup( + module, runPeriodically(() => higherOrderOperation.refreshAllLocations(), 10000), ); From 404bc724fbc013a1c6160756b8a7ee1ed143ba16 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Mon, 15 Jun 2020 23:11:10 +0200 Subject: [PATCH 10/12] refactor(cli): split out bundling config for BE --- packages/backend-common/package.json | 2 +- packages/cli/config/tsconfig.json | 2 +- packages/cli/src/lib/bundler/backend.ts | 5 +- packages/cli/src/lib/bundler/bundle.ts | 1 - packages/cli/src/lib/bundler/config.ts | 122 ++++++++++++++------- packages/cli/src/lib/bundler/server.ts | 1 - packages/cli/src/lib/bundler/transforms.ts | 6 +- packages/cli/src/lib/bundler/types.ts | 3 +- yarn.lock | 59 ++++++++++ 9 files changed, 152 insertions(+), 49 deletions(-) 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" From 495dd1f50f8e4b537b24d4334c0737dcd0a01f77 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Tue, 16 Jun 2020 09:37:21 +0200 Subject: [PATCH 11/12] fix: webpack-env types to the cli --- packages/cli/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/package.json b/packages/cli/package.json index 785e059219..a4c862351e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -41,6 +41,7 @@ "@sucrase/webpack-loader": "^2.0.0", "@types/start-server-webpack-plugin": "^2.2.0", "@types/webpack-node-externals": "^1.7.1", + "@types/webpack-env": "^1.15.2", "bfj": "^7.0.2", "chalk": "^4.0.0", "chokidar": "^3.3.1", From 016e2d8855b879a6fcebc571aac09380242c78c6 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Tue, 16 Jun 2020 09:49:31 +0200 Subject: [PATCH 12/12] fix(backend-common): move some @types to devdeps for now --- packages/backend-common/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index d8aad7945f..9b92540488 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -27,8 +27,6 @@ "clean": "backstage-cli clean" }, "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 +42,9 @@ "@types/express": "^4.17.6", "@types/http-errors": "^1.6.3", "@types/morgan": "^1.9.0", + "@types/stoppable": "^1.1.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",