diff --git a/package.json b/package.json index 42c823e23c..d80f2ecd8d 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,9 @@ "dev-build": "concurrently yarn:compile:*", "debug-build": "concurrently yarn:compile:main yarn:compile:extension-types", "dev-run": "nodemon --watch static/build/main.js --exec \"electron --remote-debugging-port=9223 --inspect .\"", - "dev:main": "yarn run compile:main --watch", - "dev:renderer": "yarn run webpack-dev-server --config webpack.renderer.ts", - "dev:extension-types": "yarn run compile:extension-types --watch", + "dev:main": "yarn run compile:main --watch --progress", + "dev:renderer": "yarn run webpack-dev-server --config webpack.renderer.ts --progress", + "dev:extension-types": "yarn run compile:extension-types --watch --progress", "compile": "env NODE_ENV=production concurrently yarn:compile:*", "compile:main": "yarn run webpack --config webpack.main.ts", "compile:renderer": "yarn run webpack --config webpack.renderer.ts", @@ -244,6 +244,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-material-ui-carousel": "^2.3.8", + "react-refresh-typescript": "^2.0.3", "react-router": "^5.2.0", "react-virtualized-auto-sizer": "^1.0.6", "readable-stream": "^3.6.0", @@ -366,7 +367,7 @@ "randomcolor": "^0.6.2", "raw-loader": "^4.0.2", "react-beautiful-dnd": "^13.1.0", - "react-refresh": "^0.9.0", + "react-refresh": "^0.11.0", "react-router-dom": "^5.3.0", "react-select": "3.2.0", "react-select-event": "^5.1.0", @@ -378,7 +379,7 @@ "style-loader": "^2.0.0", "tailwindcss": "^3.0.7", "ts-jest": "26.5.6", - "ts-loader": "^7.0.5", + "ts-loader": "^9.2.6", "ts-node": "^10.4.0", "type-fest": "^1.0.2", "typed-emitter": "^1.4.0", diff --git a/src/common/getTSLoader.ts b/src/common/getTSLoader.ts index ca93875398..41aaf78308 100644 --- a/src/common/getTSLoader.ts +++ b/src/common/getTSLoader.ts @@ -4,18 +4,17 @@ */ import esbuild from "esbuild"; +import type { Options as TSLoaderOptions } from "ts-loader"; /** * A function returning webpack ts/tsx loader - * * depends on env LENS_DEV_USE_ESBUILD_LOADER to use esbuild-loader (faster) or good-old ts-loader - * - * @param testRegExp - the regex for webpack to conditional find the files * @returns ts/tsx webpack loader configuration object */ -const getTSLoader = ( - testRegExp: RegExp, transpileOnly = true, -) => { +const getTSLoader = (options: Partial = {}, testRegExp?: RegExp) => { + testRegExp ??= /\.tsx?$/; // by default covers react/jsx-stuff + options.transpileOnly ??= true; // requirement for "react-refresh-typescript" + if (process.env.LENS_DEV_USE_ESBUILD_LOADER === "true") { console.info(`\nšŸš€ using esbuild-loader for ts(x)`); @@ -34,10 +33,8 @@ const getTSLoader = ( test: testRegExp, exclude: /node_modules/, use: { - loader: "ts-loader", - options: { - transpileOnly, - }, + loader: require.resolve("ts-loader"), + options, }, }; }; diff --git a/src/main/router.ts b/src/main/router.ts index 27243fa09d..0bd4d554ab 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -9,8 +9,21 @@ import type http from "http"; import path from "path"; import { readFile } from "fs-extra"; import type { Cluster } from "../common/cluster/cluster"; -import { apiPrefix, appName, publicPath } from "../common/vars"; -import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes"; +import { + apiPrefix, + appName, + isDevelopment, + publicPath, + webpackDevServerPort, +} from "../common/vars"; +import { + HelmApiRoute, + KubeconfigRoute, + MetricsRoute, + PortForwardRoute, + ResourceApplierApiRoute, + VersionRoute, +} from "./routes"; import logger from "./logger"; export interface RouterRequestOpts { @@ -80,7 +93,13 @@ export class Router { const routeFound = !matchingRoute.isBoom; if (routeFound) { - const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params }); + const request = await this.getRequest({ + req, + res, + cluster, + url, + params: matchingRoute.params, + }); await matchingRoute.route(request); @@ -110,7 +129,11 @@ export class Router { }; } - protected static async handleStaticFile({ params, response }: LensApiRequest): Promise { + protected static async handleStaticFile({ + params, + response, + raw: { req }, + }: LensApiRequest): Promise { let filePath = params.path; for (let retryCount = 0; retryCount < 5; retryCount += 1) { @@ -124,20 +147,24 @@ export class Router { } try { - // const filename = path.basename(req.url); + const filename = path.basename(req.url); + // redirect requests to [appName].js, [appName].html /sockjs-node/ to webpack-dev-server (for hot-reload support) - // const toWebpackDevServer = filename.includes(appName) || filename.includes("hot-update") || req.url.includes("sockjs-node"); - // - // if (isDevelopment /*&& toWebpackDevServer*/) { - // const redirectLocation = `http://0.0.0.0:${webpackDevServerPort}${req.url}`; - // - // logger.info(`[ROUTER]: redirecting to dev-server url: ${redirectLocation}`); - // - // response.statusCode = 307; - // response.setHeader("Location", redirectLocation); - // - // return response.end(); - // } + const toWebpackDevServer = [appName, "hot-update"].includes(filename) || req.url.includes("sockjs-node"); + + logger.info(`[ROUTER]: handling request`, { + url: req.url, + isWebpackRequestUpdate: toWebpackDevServer, + }); + + if (isDevelopment && toWebpackDevServer) { + const redirectLocation = `http://0.0.0.0:${webpackDevServerPort}${req.url}`; + + response.statusCode = 307; + response.setHeader("Location", redirectLocation); + + return response.end(); + } const data = await readFile(asset); @@ -163,33 +190,84 @@ export class Router { this.router.add({ method: "get", path: "/{path*}" }, Router.handleStaticFile); this.router.add({ method: "get", path: "/version" }, VersionRoute.getVersion); - this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, KubeconfigRoute.routeServiceAccountRoute); + this.router.add({ + method: "get", + path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}`, + }, KubeconfigRoute.routeServiceAccountRoute); // Metrics API this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, MetricsRoute.routeMetrics); - this.router.add({ method: "get", path: `${apiPrefix}/metrics/providers` }, MetricsRoute.routeMetricsProviders); + this.router.add({ + method: "get", + path: `${apiPrefix}/metrics/providers`, + }, MetricsRoute.routeMetricsProviders); // Port-forward API (the container port and local forwarding port are obtained from the query parameters) - this.router.add({ method: "post", path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}` }, this.dependencies.routePortForward); - this.router.add({ method: "get", path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}` }, PortForwardRoute.routeCurrentPortForward); - this.router.add({ method: "delete", path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}` }, PortForwardRoute.routeCurrentPortForwardStop); + this.router.add({ + method: "post", + path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`, + }, this.dependencies.routePortForward); + this.router.add({ + method: "get", + path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`, + }, PortForwardRoute.routeCurrentPortForward); + this.router.add({ + method: "delete", + path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`, + }, PortForwardRoute.routeCurrentPortForwardStop); // Helm API this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, HelmApiRoute.listCharts); - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, HelmApiRoute.getChart); - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, HelmApiRoute.getChartValues); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/charts/{repo}/{chart}`, + }, HelmApiRoute.getChart); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/charts/{repo}/{chart}/values`, + }, HelmApiRoute.getChartValues); - this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, HelmApiRoute.installChart); - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.updateRelease); - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, HelmApiRoute.rollbackRelease); - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, HelmApiRoute.listReleases); - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.getRelease); - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, HelmApiRoute.getReleaseValues); - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, HelmApiRoute.getReleaseHistory); - this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.deleteRelease); + this.router.add({ + method: "post", + path: `${apiPrefix}/v2/releases`, + }, HelmApiRoute.installChart); + this.router.add({ + method: `put`, + path: `${apiPrefix}/v2/releases/{namespace}/{release}`, + }, HelmApiRoute.updateRelease); + this.router.add({ + method: `put`, + path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback`, + }, HelmApiRoute.rollbackRelease); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/releases/{namespace?}`, + }, HelmApiRoute.listReleases); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/releases/{namespace}/{release}`, + }, HelmApiRoute.getRelease); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/releases/{namespace}/{release}/values`, + }, HelmApiRoute.getReleaseValues); + this.router.add({ + method: "get", + path: `${apiPrefix}/v2/releases/{namespace}/{release}/history`, + }, HelmApiRoute.getReleaseHistory); + this.router.add({ + method: "delete", + path: `${apiPrefix}/v2/releases/{namespace}/{release}`, + }, HelmApiRoute.deleteRelease); // Resource Applier API - this.router.add({ method: "post", path: `${apiPrefix}/stack` }, ResourceApplierApiRoute.applyResource); - this.router.add({ method: "patch", path: `${apiPrefix}/stack` }, ResourceApplierApiRoute.patchResource); + this.router.add({ + method: "post", + path: `${apiPrefix}/stack`, + }, ResourceApplierApiRoute.applyResource); + this.router.add({ + method: "patch", + path: `${apiPrefix}/stack`, + }, ResourceApplierApiRoute.patchResource); } } diff --git a/webpack.main.ts b/webpack.main.ts index 9d82e0f9b8..e84d5a1ee1 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -42,7 +42,7 @@ configs.push((): webpack.Configuration => { test: /\.node$/, use: "node-loader", }, - getTSLoader(/\.ts$/), + getTSLoader({}, /\.ts$/), ], }, plugins: [ diff --git a/webpack.renderer.ts b/webpack.renderer.ts index 16d0cd1179..df95131a61 100755 --- a/webpack.renderer.ts +++ b/webpack.renderer.ts @@ -10,6 +10,7 @@ import HtmlWebpackPlugin from "html-webpack-plugin"; import MiniCssExtractPlugin from "mini-css-extract-plugin"; import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"; import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"; +import ReactRefreshTypescript from "react-refresh-typescript"; import MonacoWebpackPlugin from "monaco-editor-webpack-plugin"; import getTSLoader from "./src/common/getTSLoader"; import CircularDependencyPlugin from "circular-dependency-plugin"; @@ -42,11 +43,9 @@ export function webpackLensRenderer(): webpack.Configuration { port: webpackDevServerPort, static: buildDir, // aka `devServer.contentBase` in webpack@4 hot: true, - historyApiFallback: true, client: { logging: isDevelopment ? "verbose" : "error", - overlay: false, - progress: true, + overlay: true, }, }, name: "lens-app", @@ -87,7 +86,11 @@ export function webpackLensRenderer(): webpack.Configuration { test: /\.node$/, use: "node-loader", }, - getTSLoader(/\.tsx?$/), + getTSLoader({ + getCustomTransformers: () => ({ + before: isDevelopment ? [ReactRefreshTypescript as any] : [], + }), + }), filesAndIconsWebpackRule(), fontsLoaderWebpackRule(), cssModulesWebpackRule(), diff --git a/yarn.lock b/yarn.lock index 7a57eb259d..ef14b13075 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3455,7 +3455,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -4961,16 +4961,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -enhanced-resolve@^5.8.3: +enhanced-resolve@^5.0.0, enhanced-resolve@^5.8.3: version "5.8.3" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== @@ -5012,7 +5003,7 @@ errno@^0.1.1: dependencies: prr "~1.0.1" -errno@^0.1.3, errno@~0.1.7: +errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== @@ -8619,15 +8610,6 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" @@ -8968,14 +8950,6 @@ memfs@^3.2.2: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -11053,10 +11027,15 @@ react-redux@^7.2.0: prop-types "^15.7.2" react-is "^16.13.1" -react-refresh@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" - integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== +react-refresh-typescript@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/react-refresh-typescript/-/react-refresh-typescript-2.0.3.tgz#73fd93befd2a0a0fd8041c39cc82b8c04aec00c3" + integrity sha512-CnR+UkpCFUIxW3u+KPxc6UhSO3M3aQxd9XCvgdry4a22LFwwITnjbANFUKtPGxA/Skw3PbZJrLiZ08UQnpXprQ== + +react-refresh@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" + integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== react-router-dom@^5.3.0: version "5.3.0" @@ -13097,16 +13076,15 @@ ts-jest@26.5.6: semver "7.x" yargs-parser "20.x" -ts-loader@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.5.tgz#789338fb01cb5dc0a33c54e50558b34a73c9c4c5" - integrity sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig== +ts-loader@^9.2.6: + version "9.2.6" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.6.tgz#9937c4dd0a1e3dbbb5e433f8102a6601c6615d74" + integrity sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw== dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" + chalk "^4.1.0" + enhanced-resolve "^5.0.0" micromatch "^4.0.0" - semver "^6.0.0" + semver "^7.3.4" ts-node@^10.4.0: version "10.4.0"