1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Webpack quality of life improvements for dev mode (#4980)

This commit is contained in:
Jari Kolehmainen 2022-03-08 16:48:16 +02:00 committed by GitHub
parent adf3b8dc60
commit a4954b9f8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 6902 additions and 11329 deletions

View File

@ -23,16 +23,14 @@ node_modules: yarn.lock
binaries/client: node_modules binaries/client: node_modules
yarn download-bins yarn download-bins
static/build/LensDev.html: node_modules
yarn compile:renderer
.PHONY: compile-dev .PHONY: compile-dev
compile-dev: node_modules compile-dev: node_modules
yarn compile:main --cache yarn compile:main --cache
yarn compile:renderer --cache yarn compile:renderer --cache
.PHONY: dev .PHONY: dev
dev: binaries/client build-extensions static/build/LensDev.html dev: binaries/client build-extensions
rm -rf static/build/
yarn dev yarn dev
.PHONY: lint .PHONY: lint
@ -62,10 +60,11 @@ ifeq "$(DETECTED_OS)" "Windows"
endif endif
yarn run electron-builder --publish onTag $(ELECTRON_BUILDER_EXTRA_ARGS) yarn run electron-builder --publish onTag $(ELECTRON_BUILDER_EXTRA_ARGS)
.NOTPARALLEL: $(extension_node_modules)
$(extension_node_modules): node_modules $(extension_node_modules): node_modules
cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund --no-save
$(extension_dists): src/extensions/npm/extensions/dist $(extension_dists): src/extensions/npm/extensions/dist $(extension_node_modules)
cd $(@:/dist=) && ../../node_modules/.bin/npm run build cd $(@:/dist=) && ../../node_modules/.bin/npm run build
.PHONY: clean-old-extensions .PHONY: clean-old-extensions
@ -73,7 +72,7 @@ clean-old-extensions:
find ./extensions -mindepth 1 -maxdepth 1 -type d '!' -exec test -e '{}/package.json' \; -exec rm -rf {} \; find ./extensions -mindepth 1 -maxdepth 1 -type d '!' -exec test -e '{}/package.json' \; -exec rm -rf {} \;
.PHONY: build-extensions .PHONY: build-extensions
build-extensions: node_modules clean-old-extensions $(extension_node_modules) $(extension_dists) build-extensions: node_modules clean-old-extensions $(extension_dists)
.PHONY: test-extensions .PHONY: test-extensions
test-extensions: $(extension_node_modules) test-extensions: $(extension_node_modules)

File diff suppressed because it is too large Load Diff

View File

@ -8,18 +8,15 @@
"styles": [] "styles": []
}, },
"scripts": { "scripts": {
"build": "webpack && npm pack", "build": "npx webpack && npm pack",
"dev": "webpack --watch", "dev": "npx webpack -- --watch",
"test": "echo NO TESTS" "test": "echo NO TESTS"
}, },
"files": [ "files": [
"dist/**/*" "dist/**/*"
], ],
"dependencies": {},
"devDependencies": { "devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions", "@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"ts-loader": "latest", "npm": "^8.5.3"
"typescript": "latest",
"webpack": "latest"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,9 @@
"styles": [] "styles": []
}, },
"scripts": { "scripts": {
"build": "webpack && npm pack", "build": "npx webpack && npm pack",
"dev": "webpack --watch", "dev": "npx webpack -- --watch",
"test": "jest --passWithNoTests --env=jsdom src $@", "test": "npx jest --passWithNoTests --env=jsdom src $@",
"clean": "rm -rf dist/ && rm *.tgz" "clean": "rm -rf dist/ && rm *.tgz"
}, },
"files": [ "files": [
@ -19,10 +19,7 @@
], ],
"devDependencies": { "devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions", "@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"semver": "^7.3.2", "npm": "^8.5.3",
"jest": "latest", "semver": "^7.3.2"
"ts-loader": "latest",
"typescript": "latest",
"webpack": "latest"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,9 @@
"styles": [] "styles": []
}, },
"scripts": { "scripts": {
"build": "webpack && npm pack", "build": "npx webpack && npm pack",
"dev": "webpack --watch", "dev": "npx webpack -- --watch",
"test": "jest --passWithNoTests --env=jsdom src $@" "test": "npx jest --passWithNoTests --env=jsdom src $@"
}, },
"files": [ "files": [
"dist/**/*" "dist/**/*"
@ -18,9 +18,6 @@
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions", "@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "latest", "npm": "^8.5.3"
"ts-loader": "latest",
"typescript": "latest",
"webpack": "latest"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,9 @@
"styles": [] "styles": []
}, },
"scripts": { "scripts": {
"build": "webpack && npm pack", "build": "npx webpack && npm pack",
"dev": "webpack --watch", "dev": "npx webpack -- --watch",
"test": "jest --passWithNoTests --env=jsdom src $@" "test": "npx jest --passWithNoTests --env=jsdom src $@"
}, },
"files": [ "files": [
"dist/**/*" "dist/**/*"
@ -18,9 +18,6 @@
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions", "@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "latest", "npm": "^8.5.3"
"ts-loader": "latest",
"typescript": "latest",
"webpack": "latest"
} }
} }

View File

@ -15,10 +15,9 @@
"dev": "concurrently -i -k \"yarn run dev-run -C\" yarn:dev:*", "dev": "concurrently -i -k \"yarn run dev-run -C\" yarn:dev:*",
"dev-build": "concurrently yarn:compile:*", "dev-build": "concurrently yarn:compile:*",
"debug-build": "concurrently yarn:compile:main yarn:compile:extension-types", "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-run": "nodemon --watch ./static/build/main.js --exec \"electron --remote-debugging-port=9223 --inspect .\"",
"dev:main": "yarn run compile:main --watch --progress", "dev:main": "yarn run compile:main --watch --progress",
"dev:renderer": "yarn run compile:renderer --watch --progress", "dev:renderer": "yarn run ts-node webpack.dev-server.ts",
"dev:extension-types": "yarn run compile:extension-types --watch --progress",
"compile": "env NODE_ENV=production concurrently yarn:compile:*", "compile": "env NODE_ENV=production concurrently yarn:compile:*",
"compile:main": "yarn run webpack --config webpack.main.ts", "compile:main": "yarn run webpack --config webpack.main.ts",
"compile:renderer": "yarn run webpack --config webpack.renderer.ts", "compile:renderer": "yarn run webpack --config webpack.renderer.ts",

View File

@ -7,10 +7,11 @@
import { injectSystemCAs } from "../common/system-ca"; import { injectSystemCAs } from "../common/system-ca";
import * as Mobx from "mobx"; import * as Mobx from "mobx";
import httpProxy from "http-proxy";
import * as LensExtensionsCommonApi from "../extensions/common-api"; import * as LensExtensionsCommonApi from "../extensions/common-api";
import * as LensExtensionsMainApi from "../extensions/main-api"; import * as LensExtensionsMainApi from "../extensions/main-api";
import { app, autoUpdater, dialog, powerMonitor } from "electron"; import { app, autoUpdater, dialog, powerMonitor } from "electron";
import { appName, isIntegrationTesting, isMac, isWindows, productName, isDevelopment } from "../common/vars"; import { appName, isIntegrationTesting, isMac, isWindows, productName } from "../common/vars";
import { LensProxy } from "./lens-proxy"; import { LensProxy } from "./lens-proxy";
import { WindowManager } from "./window-manager"; import { WindowManager } from "./window-manager";
import { ClusterManager } from "./cluster-manager"; import { ClusterManager } from "./cluster-manager";
@ -164,7 +165,7 @@ di.runSetups().then(() => {
const router = di.inject(routerInjectable); const router = di.inject(routerInjectable);
const shellApiRequest = di.inject(shellApiRequestInjectable); const shellApiRequest = di.inject(shellApiRequestInjectable);
const lensProxy = LensProxy.createInstance(router, { const lensProxy = LensProxy.createInstance(router, httpProxy.createProxy(), {
getClusterForRequest: (req) => ClusterManager.getInstance().getClusterForRequest(req), getClusterForRequest: (req) => ClusterManager.getInstance().getClusterForRequest(req),
kubeApiRequest, kubeApiRequest,
shellApiRequest, shellApiRequest,
@ -227,16 +228,6 @@ di.runSetups().then(() => {
logger.info("🖥️ Starting WindowManager"); logger.info("🖥️ Starting WindowManager");
const windowManager = WindowManager.createInstance(); const windowManager = WindowManager.createInstance();
// Override main content view url to local webpack-dev-server to support HMR / live-reload
if (isDevelopment) {
const { createDevServer } = await import("../../webpack.dev-server");
const devServer = createDevServer(lensProxy.port);
await devServer.start();
windowManager.mainContentUrl = `http://localhost:${devServer.options.port}`;
}
const menuItems = di.inject(electronMenuItemsInjectable); const menuItems = di.inject(electronMenuItemsInjectable);
const trayMenuItems = di.inject(trayMenuItemsInjectable); const trayMenuItems = di.inject(trayMenuItemsInjectable);

View File

@ -6,7 +6,7 @@
import type net from "net"; import type net from "net";
import type http from "http"; import type http from "http";
import spdy from "spdy"; import spdy from "spdy";
import httpProxy from "http-proxy"; import type httpProxy from "http-proxy";
import { apiPrefix, apiKubePrefix } from "../common/vars"; import { apiPrefix, apiKubePrefix } from "../common/vars";
import type { Router } from "./router"; import type { Router } from "./router";
import type { ContextHandler } from "./context-handler/context-handler"; import type { ContextHandler } from "./context-handler/context-handler";
@ -57,14 +57,15 @@ export class LensProxy extends Singleton {
protected proxyServer: http.Server; protected proxyServer: http.Server;
protected closed = false; protected closed = false;
protected retryCounters = new Map<string, number>(); protected retryCounters = new Map<string, number>();
protected proxy = this.createProxy();
protected getClusterForRequest: GetClusterForRequest; protected getClusterForRequest: GetClusterForRequest;
public port: number; public port: number;
constructor(protected router: Router, { shellApiRequest, kubeApiRequest, getClusterForRequest }: LensProxyFunctions) { constructor(protected router: Router, protected proxy: httpProxy, { shellApiRequest, kubeApiRequest, getClusterForRequest }: LensProxyFunctions) {
super(); super();
this.configureProxy(proxy);
this.getClusterForRequest = getClusterForRequest; this.getClusterForRequest = getClusterForRequest;
this.proxyServer = spdy.createServer({ this.proxyServer = spdy.createServer({
@ -82,7 +83,9 @@ export class LensProxy extends Singleton {
const cluster = getClusterForRequest(req); const cluster = getClusterForRequest(req);
if (!cluster) { if (!cluster) {
return void logger.error(`[LENS-PROXY]: Could not find cluster for upgrade request from url=${req.url}`); logger.error(`[LENS-PROXY]: Could not find cluster for upgrade request from url=${req.url}`);
return socket.destroy();
} }
const reqHandler = isInternal ? shellApiRequest : kubeApiRequest; const reqHandler = isInternal ? shellApiRequest : kubeApiRequest;
@ -163,9 +166,7 @@ export class LensProxy extends Singleton {
this.closed = true; this.closed = true;
} }
protected createProxy(): httpProxy { protected configureProxy(proxy: httpProxy): httpProxy {
const proxy = httpProxy.createProxyServer();
proxy.on("proxyRes", (proxyRes, req, res) => { proxy.on("proxyRes", (proxyRes, req, res) => {
const retryCounterId = this.getRequestId(req); const retryCounterId = this.getRequestId(req);

View File

@ -6,6 +6,7 @@
import Call from "@hapi/call"; import Call from "@hapi/call";
import Subtext from "@hapi/subtext"; import Subtext from "@hapi/subtext";
import type http from "http"; import type http from "http";
import type httpProxy from "http-proxy";
import path from "path"; import path from "path";
import { readFile } from "fs-extra"; import { readFile } from "fs-extra";
import type { Cluster } from "../common/cluster/cluster"; import type { Cluster } from "../common/cluster/cluster";
@ -40,6 +41,7 @@ export interface LensApiRequest<P = any> {
query: URLSearchParams; query: URLSearchParams;
raw: { raw: {
req: http.IncomingMessage; req: http.IncomingMessage;
res: http.ServerResponse;
}; };
} }
@ -62,6 +64,7 @@ function getMimeType(filename: string) {
interface Dependencies { interface Dependencies {
routePortForward: (request: LensApiRequest) => Promise<void>; routePortForward: (request: LensApiRequest) => Promise<void>;
httpProxy?: httpProxy;
} }
export class Router { export class Router {
@ -101,7 +104,7 @@ export class Router {
cluster, cluster,
path: url.pathname, path: url.pathname,
raw: { raw: {
req, req, res,
}, },
response: res, response: res,
query: url.searchParams, query: url.searchParams,
@ -140,12 +143,26 @@ export class Router {
filePath = `${publicPath}/${appName}.html`; filePath = `${publicPath}/${appName}.html`;
} }
} }
} }
protected addRoutes() { protected addRoutes() {
// Static assets // Static assets
if (this.dependencies.httpProxy) {
this.router.add({ method: "get", path: "/{path*}" }, (apiReq: LensApiRequest) => {
const { req, res } = apiReq.raw;
if (req.url === "/" || !req.url.startsWith("/build/")) {
req.url = `${publicPath}/${appName}.html`;
}
this.dependencies.httpProxy.web(req, res, {
target: "http://127.0.0.1:8080",
});
});
} else {
this.router.add({ method: "get", path: "/{path*}" }, Router.handleStaticFile); this.router.add({ method: "get", path: "/{path*}" }, Router.handleStaticFile);
}
this.router.add({ method: "get", path: "/version" }, VersionRoute.getVersion); 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);

View File

@ -3,6 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isDevelopmentInjectable from "../../common/vars/is-development.injectable";
import httpProxy from "http-proxy";
import { Router } from "../router"; import { Router } from "../router";
import routePortForwardInjectable import routePortForwardInjectable
from "../routes/port-forward/route-port-forward/route-port-forward.injectable"; from "../routes/port-forward/route-port-forward/route-port-forward.injectable";
@ -10,9 +12,15 @@ import routePortForwardInjectable
const routerInjectable = getInjectable({ const routerInjectable = getInjectable({
id: "router", id: "router",
instantiate: (di) => new Router({ instantiate: (di) => {
const isDevelopment = di.inject(isDevelopmentInjectable);
const proxy = isDevelopment ? httpProxy.createProxy() : undefined;
return new Router({
routePortForward: di.inject(routePortForwardInjectable), routePortForward: di.inject(routePortForwardInjectable),
}), httpProxy: proxy,
});
},
}); });
export default routerInjectable; export default routerInjectable;

View File

@ -9,20 +9,18 @@ import { webpackLensRenderer } from "./webpack.renderer";
import { buildDir } from "./src/common/vars"; import { buildDir } from "./src/common/vars";
import logger from "./src/common/logger"; import logger from "./src/common/logger";
export interface DevServer extends WebpackDevServer {
}
/** /**
* Creates `webpack-dev-server` * Creates `webpack-dev-server`
* API docs: * API docs:
* @url https://webpack.js.org/configuration/dev-server/ * @url https://webpack.js.org/configuration/dev-server/
* @url https://github.com/chimurai/http-proxy-middleware * @url https://github.com/chimurai/http-proxy-middleware
*/ */
export function createDevServer(lensProxyPort: number): DevServer { function createDevServer(): WebpackDevServer {
const config = webpackLensRenderer({ showVars: false }); const config = webpackLensRenderer({ showVars: false });
const compiler = Webpack(config); const compiler = Webpack(config);
const server = new WebpackDevServer({ const server = new WebpackDevServer({
setupExitSignals: true,
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
}, },
@ -31,17 +29,13 @@ export function createDevServer(lensProxyPort: number): DevServer {
static: buildDir, // aka `devServer.contentBase` in webpack@4 static: buildDir, // aka `devServer.contentBase` in webpack@4
hot: "only", // use HMR only without errors hot: "only", // use HMR only without errors
liveReload: false, liveReload: false,
devMiddleware: {
writeToDisk: false,
index: "OpenLensDev.html",
publicPath: "/build",
},
proxy: { proxy: {
"*": { "^/$": "/build/",
router(req) {
logger.silly(`[WEBPACK-DEV-SERVER]: proxy path ${req.path}`, req.headers);
return `http://localhost:${lensProxyPort}`;
},
secure: false, // allow http connections
ws: true, // proxy websockets, e.g. terminal
logLevel: "error",
},
}, },
client: { client: {
overlay: false, // don't show warnings and errors on top of rendered app view overlay: false, // don't show warnings and errors on top of rendered app view
@ -53,3 +47,7 @@ export function createDevServer(lensProxyPort: number): DevServer {
return server; return server;
} }
const server = createDevServer();
server.start();

View File

@ -19,11 +19,12 @@ configs.push((): webpack.Configuration => {
const { mainDir, buildDir, isDevelopment } = vars; const { mainDir, buildDir, isDevelopment } = vars;
return { return {
name: "lens-app-main",
context: __dirname, context: __dirname,
target: "electron-main", target: "electron-main",
mode: isDevelopment ? "development" : "production", mode: isDevelopment ? "development" : "production",
devtool: isDevelopment ? "cheap-module-source-map" : "source-map", devtool: isDevelopment ? "cheap-module-source-map" : "source-map",
cache: isDevelopment, cache: isDevelopment ? { type: "filesystem" } : false,
entry: { entry: {
main: path.resolve(mainDir, "index.ts"), main: path.resolve(mainDir, "index.ts"),
}, },
@ -49,7 +50,6 @@ configs.push((): webpack.Configuration => {
}, },
plugins: [ plugins: [
new ForkTsCheckerPlugin(), new ForkTsCheckerPlugin(),
new CircularDependencyPlugin({ new CircularDependencyPlugin({
cwd: __dirname, cwd: __dirname,
exclude: /node_modules/, exclude: /node_modules/,

View File

@ -24,11 +24,11 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura
return { return {
target: "electron-renderer", target: "electron-renderer",
name: "lens-app", name: "lens-app-renderer",
mode: isDevelopment ? "development" : "production", mode: isDevelopment ? "development" : "production",
// https://webpack.js.org/configuration/devtool/ (see description of each option) // https://webpack.js.org/configuration/devtool/ (see description of each option)
devtool: isDevelopment ? "cheap-module-source-map" : "source-map", devtool: isDevelopment ? "cheap-module-source-map" : "source-map",
cache: isDevelopment, cache: isDevelopment ? { type: "filesystem" } : false,
entry: { entry: {
[appName]: path.resolve(rendererDir, "bootstrap.tsx"), [appName]: path.resolve(rendererDir, "bootstrap.tsx"),
}, },