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

refactoring, split webpack configs + get rid of electron-webpack

This commit is contained in:
Roman 2020-06-12 22:22:38 +03:00
parent a4d66fffda
commit 9aa815bc14
18 changed files with 407 additions and 1329 deletions

View File

@ -1,8 +1,6 @@
{ {
"presets": [ "presets": [
[ "@babel/preset-env",
"@babel/preset-env", {"modules": "commonjs"}
],
"@babel/preset-react", "@babel/preset-react",
"@lingui/babel-preset-react" "@lingui/babel-preset-react"
], ],

View File

@ -5,10 +5,13 @@
"version": "3.5.0-beta.1", "version": "3.5.0-beta.1",
"main": "src/main", "main": "src/main",
"scripts": { "scripts": {
"dev": "DEBUG=true electron-webpack dev", "dev": "DEBUG=true concurrently yarn:dev:*",
"compile": "yarn download-bins && yarn i18n:compile && electron-webpack compile", "dev:main": "webpack-cli --watch --cache --config webpack.main.ts",
"compile:main": "electron-webpack main", "dev:render": "webpack-cli --watch --cache --config webpack.renderer.ts",
"compile:renderer": "electron-webpack renderer", "compile": "concurrently 'yarn download-bins' 'yarn i18n:compile' 'yarn make-dll' && concurrently yarn:compile:*",
"compile:main": "webpack -p --progress --config webpack.main.ts",
"compile:renderer": "webpack -p --progress --config webpack.renderer.ts",
"make-dll": "webpack --config webpack.dll.ts",
"build:linux": "yarn compile && electron-builder --linux --dir -c.productName=LensDev", "build:linux": "yarn compile && electron-builder --linux --dir -c.productName=LensDev",
"build:mac": "yarn compile && electron-builder --mac --dir -c.productName=LensDev", "build:mac": "yarn compile && electron-builder --mac --dir -c.productName=LensDev",
"build:win": "yarn compile && electron-builder --win --dir -c.productName=LensDev", "build:win": "yarn compile && electron-builder --win --dir -c.productName=LensDev",
@ -17,7 +20,7 @@
"dist": "yarn compile && electron-builder -p onTag", "dist": "yarn compile && electron-builder -p onTag",
"dist:win": "yarn compile && electron-builder -p onTag --x64 --ia32", "dist:win": "yarn compile && electron-builder -p onTag --x64 --ia32",
"dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null", "dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null",
"postinstall": "concurrently patch-package", "postinstall": "patch-package && concurrently 'electron-builder install-app-deps' 'yarn make-dll'",
"i18n:extract": "lingui extract", "i18n:extract": "lingui extract",
"i18n:compile": "lingui compile", "i18n:compile": "lingui compile",
"download-bins": "concurrently yarn:download:*", "download-bins": "concurrently yarn:download:*",
@ -34,18 +37,6 @@
"engines": { "engines": {
"node": ">=12.0 <13.0" "node": ">=12.0 <13.0"
}, },
"electronWebpack": {
"commonSourceDirectory": "./src/common",
"staticSourceDirectory": "./static",
"main": {
"sourceDirectory": "./src/main"
},
"renderer": {
"sourceDirectory": "./src/renderer",
"template": "./src/renderer/template.html",
"webpackConfig": "./src/renderer/webpack.renderer.js"
}
},
"lingui": { "lingui": {
"locales": [ "locales": [
"en", "en",
@ -56,11 +47,6 @@
"sourceLocale": "en", "sourceLocale": "en",
"fallbackLocale": "en", "fallbackLocale": "en",
"compileNamespace": "cjs", "compileNamespace": "cjs",
"extractBabelOptions": {
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
},
"catalogs": [ "catalogs": [
{ {
"path": "./locales/{locale}/messages", "path": "./locales/{locale}/messages",
@ -225,9 +211,11 @@
"@types/dompurify": "^2.0.2", "@types/dompurify": "^2.0.2",
"@types/hapi": "^18.0.3", "@types/hapi": "^18.0.3",
"@types/hoist-non-react-statics": "^3.3.1", "@types/hoist-non-react-statics": "^3.3.1",
"@types/html-webpack-plugin": "^3.2.3",
"@types/jest": "^25.2.3", "@types/jest": "^25.2.3",
"@types/material-ui": "^0.21.7", "@types/material-ui": "^0.21.7",
"@types/md5-file": "^4.0.2", "@types/md5-file": "^4.0.2",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/react": "^16.9.35", "@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8", "@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.5", "@types/react-router-dom": "^5.1.5",
@ -239,6 +227,7 @@
"@types/shelljs": "^0.8.8", "@types/shelljs": "^0.8.8",
"@types/tcp-port-used": "^1.0.0", "@types/tcp-port-used": "^1.0.0",
"@types/tempy": "^0.3.0", "@types/tempy": "^0.3.0",
"@types/terser-webpack-plugin": "^3.0.0",
"@types/universal-analytics": "^0.4.4", "@types/universal-analytics": "^0.4.4",
"@types/uuid": "^8.0.0", "@types/uuid": "^8.0.0",
"@types/webdriverio": "^4.13.0", "@types/webdriverio": "^4.13.0",
@ -247,6 +236,7 @@
"ace-builds": "^1.4.11", "ace-builds": "^1.4.11",
"ansi_up": "^4.0.4", "ansi_up": "^4.0.4",
"babel-core": "^7.0.0-beta.3", "babel-core": "^7.0.0-beta.3",
"babel-loader": "^8.1.0",
"babel-plugin-macros": "^2.8.0", "babel-plugin-macros": "^2.8.0",
"bootstrap": "^4.5.0", "bootstrap": "^4.5.0",
"bootstrap-vue": "^2.15.0", "bootstrap-vue": "^2.15.0",
@ -257,17 +247,17 @@
"dompurify": "^2.0.11", "dompurify": "^2.0.11",
"electron-builder": "^22.7.0", "electron-builder": "^22.7.0",
"electron-notarize": "^0.3.0", "electron-notarize": "^0.3.0",
"electron-webpack": "^2.8.2",
"electron-webpack-ts": "^4.0.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"flex.box": "^3.4.4", "flex.box": "^3.4.4",
"hashicon": "^0.3.0", "hashicon": "^0.3.0",
"hoist-non-react-statics": "^3.3.2", "hoist-non-react-statics": "^3.3.2",
"html-webpack-plugin": "^4.3.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"include-media": "^1.4.9", "include-media": "^1.4.9",
"jest": "^26.0.1", "jest": "^26.0.1",
"make-plural": "^6.2.1", "make-plural": "^6.2.1",
"material-design-icons": "^3.0.1", "material-design-icons": "^3.0.1",
"mini-css-extract-plugin": "^0.9.0",
"mobx": "^5.15.4", "mobx": "^5.15.4",
"mobx-observable-history": "^1.0.3", "mobx-observable-history": "^1.0.3",
"mobx-react": "^6.2.2", "mobx-react": "^6.2.2",
@ -285,8 +275,8 @@
"react-select": "^3.1.0", "react-select": "^3.1.0",
"react-window": "^1.8.5", "react-window": "^1.8.5",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"source-map-support": "^0.5.19",
"spectron": "^8.0.0", "spectron": "^8.0.0",
"terser-webpack-plugin": "^3.0.3",
"ts-jest": "^26.1.0", "ts-jest": "^26.1.0",
"ts-loader": "^7.0.5", "ts-loader": "^7.0.5",
"ts-node": "^8.10.2", "ts-node": "^8.10.2",
@ -303,7 +293,6 @@
"vuex": "^3.4.0", "vuex": "^3.4.0",
"webpack": "^4.43.0", "webpack": "^4.43.0",
"webpack-cli": "^3.3.11", "webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"xterm": "^4.6.0", "xterm": "^4.6.0",
"xterm-addon-fit": "^0.4.0" "xterm-addon-fit": "^0.4.0"
} }

View File

@ -0,0 +1,25 @@
// Setup static folder for common assets
import path from "path";
import { protocol } from "electron"
import logger from "../main/logger";
import { staticDir, staticProto } from "./vars";
export function registerStaticProtocol(rootFolder = staticDir) {
const scheme = staticProto.replace("://", "");
protocol.registerFileProtocol(scheme, (request, callback) => {
const relativePath = request.url.replace(staticProto, "");
const absPath = path.resolve(rootFolder, relativePath);
callback(absPath);
}, (error) => {
logger.debug(`Failed to register protocol "${scheme}"`, error);
})
}
export function getStaticUrl(filePath: string) {
return staticProto + filePath;
}
export function getStaticPath(filePath: string) {
return path.resolve(staticDir, filePath);
}

View File

@ -1,19 +1,21 @@
// App's common paths/flags/etc. for any process // App's common configuration for any process (main, renderer, build pipeline, etc.)
import packageInfo from "../../package.json"
import path from "path"; import path from "path";
const { main, renderer } = packageInfo.electronWebpack;
export const outDir = path.resolve(__dirname, "../dist");
export const mainDir = path.resolve(__dirname, "../", main.sourceDirectory);
export const rendererDir = path.resolve(__dirname, "../", renderer.sourceDirectory);
export const isMac = process.platform === "darwin" export const isMac = process.platform === "darwin"
export const isWindows = process.platform === "win32" export const isWindows = process.platform === "win32"
export const isProduction = process.env.NODE_ENV === "production" export const isProduction = process.env.NODE_ENV === "production"
export const isDevelopment = !isProduction; export const isDevelopment = !isProduction;
export const buildVersion = process.env.BUILD_VERSION; export const buildVersion = process.env.BUILD_VERSION;
// Paths
export const staticDir = path.resolve(__dirname, "../../static");
export const outDir = path.resolve(__dirname, "../../dist");
export const mainDir = path.resolve(__dirname, "../main");
export const rendererDir = path.resolve(__dirname, "../renderer");
// Apis
export const staticProto = "static://"
export const apiPrefix = { export const apiPrefix = {
BASE: '/api', BASE: '/api',
TERMINAL: '/api-terminal', // terminal api TERMINAL: '/api-terminal', // terminal api

View File

@ -18,6 +18,7 @@ import { shellSync } from "./shell-sync"
import { getFreePort } from "./port" import { getFreePort } from "./port"
import { mangleProxyEnv } from "./proxy-env" import { mangleProxyEnv } from "./proxy-env"
import { findMainWebContents } from "./webcontents" import { findMainWebContents } from "./webcontents"
import { registerStaticProtocol } from "../common/register-static";
import { isDevelopment, isMac } from "../common/vars"; import { isDevelopment, isMac } from "../common/vars";
mangleProxyEnv() mangleProxyEnv()
@ -41,12 +42,15 @@ async function main() {
updater.start(); updater.start();
tracker.event("app", "start"); tracker.event("app", "start");
registerStaticProtocol();
protocol.registerFileProtocol('store', (request, callback) => { protocol.registerFileProtocol('store', (request, callback) => {
const url = request.url.substr(8) const url = request.url.substr(8)
callback(path.normalize(`${app.getPath("userData")}/${url}`)) callback(path.normalize(`${app.getPath("userData")}/${url}`))
}, (error) => { }, (error) => {
if (error) console.error('Failed to register protocol') if (error) console.error('Failed to register protocol')
}) })
let port: number = null let port: number = null
// find free port // find free port
try { try {

View File

@ -1,5 +1,6 @@
import http from "http" import http from "http"
import path from "path" import path from "path"
import { readFile } from "fs"
import { Cluster } from "./cluster" import { Cluster } from "./cluster"
import { configRoute } from "./routes/config" import { configRoute } from "./routes/config"
import { helmApi } from "./helm-api" import { helmApi } from "./helm-api"
@ -8,7 +9,7 @@ import { kubeconfigRoute } from "./routes/kubeconfig"
import { metricsRoute } from "./routes/metrics" import { metricsRoute } from "./routes/metrics"
import { watchRoute } from "./routes/watch" import { watchRoute } from "./routes/watch"
import { portForwardRoute } from "./routes/port-forward" import { portForwardRoute } from "./routes/port-forward"
import { readFile } from "fs" import { getStaticPath } from "../common/register-static";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const Call = require('@hapi/call'); const Call = require('@hapi/call');
@ -84,8 +85,8 @@ export class Router {
return request return request
} }
protected handleStaticFile(file: string, response: http.ServerResponse) { protected handleStaticFile(filePath: string, response: http.ServerResponse) {
const asset = path.join(__static, file) const asset = getStaticPath(filePath);
readFile(asset, (err, data) => { readFile(asset, (err, data) => {
if (err) { if (err) {
// default to index.html so that react routes work when page is refreshed // default to index.html so that react routes work when page is refreshed

View File

@ -1,9 +1,9 @@
import path from "path"
import { BrowserWindow, shell } from "electron" import { BrowserWindow, shell } from "electron"
import { PromiseIpc } from "electron-promise-ipc" import { PromiseIpc } from "electron-promise-ipc"
import windowStateKeeper from "electron-window-state" import windowStateKeeper from "electron-window-state"
import { tracker } from "./tracker"; import { tracker } from "./tracker";
import { isDevelopment } from "../common/vars"; import { isDevelopment } from "../common/vars";
import { getStaticUrl } from "../common/register-static";
export class WindowManager { export class WindowManager {
public mainWindow: BrowserWindow = null; public mainWindow: BrowserWindow = null;
@ -32,7 +32,7 @@ export class WindowManager {
} }
}) })
if (showSplash) { if (showSplash) {
this.splashWindow.loadFile(path.join(__static, "/splash.html")) this.splashWindow.loadFile(getStaticUrl("splash.html"))
this.splashWindow.show() this.splashWindow.show()
} }

View File

@ -28,16 +28,17 @@
<script> <script>
import marked from 'marked' import marked from 'marked'
import fs from 'fs' import {readFileSync} from 'fs'
import path from "path" import { getStaticPath } from "../../../common/register-static"
export default { export default {
name: 'WhatsNewPage', name: 'WhatsNewPage',
data() { data() {
let releaseNotes = getStaticPath("RELEASE_NOTES.md");
let content = marked(readFileSync(releaseNotes, 'utf8'));
return { return {
error: "", error: "",
// eslint-disable-next-line content: content,
content: marked(fs.readFileSync(path.join(__static, "RELEASE_NOTES.md"), 'utf8')),
} }
}, },
components: {}, components: {},

View File

@ -1,8 +1,10 @@
// Renderer process // Renderer process
import "../common/system-ca" import "../common/system-ca"
import { App } from "./components/app"; // import { App } from "./components/app";
// import { appInitVue } from "./_vue"; // import { appInitVue } from "./_vue";
// appInitVue() // appInitVue()
// App.init();
App.init(); var app = document.getElementById("app")
app.innerHTML = "RUNNING!!"

View File

@ -3,8 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Lens - The Kubernetes IDE</title> <title>Lens - The Kubernetes IDE</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1">--> <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
<!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self'">-->
</head> </head>
<body> <body>

View File

@ -1,46 +0,0 @@
// fixme: convert to typescript (support webpack types, reuse vars.ts)
const path = require("path");
module.exports = function (config, env) {
const {module} = config;
const {rules} = module;
// localization support
// https://lingui.js.org/guides/typescript.html
patchLoader(".tsx", "ts-loader", loader => {
loader.options = Object.assign({}, loader.options, {
compilerOptions: {
jsx: "preserve", // @lingui/babel-preset-react
target: "es2016", // @lingui/babel-preset-react
}
})
return ["babel-loader", loader]
});
// sass common vars file import
patchLoader(".scss", "sass-loader", loader => {
loader.options = Object.assign({}, loader.options, {
prependData: '@import "vars.scss";',
sassOptions: {
includePaths: [
path.resolve(__dirname, "components")
]
}
})
return loader;
});
function patchLoader(fileType, loaderName, updater) {
let rule = rules.find(rule => fileType.match(rule.test));
if (rule) {
let loaders = [rule.use].flat();
let index = loaders.findIndex(loader => loader === loaderName || loader.loader === loaderName);
let loader = typeof loaders[index] === "string" ? {loader: loaders[index]} : loaders[index];
loaders[index] = updater(loader);
rule.use = loaders.flat();
console.info(`Patched webpack's renderer config for "${loaderName}" in ${__filename}`, loader);
}
}
return config;
}

View File

@ -1,14 +1,13 @@
{ {
"extends": "./node_modules/electron-webpack/tsconfig-base.json",
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"outDir": "./dist", "outDir": "./dist",
"jsx": "react", "jsx": "react",
"target": "ES2017", "target": "ES6",
"module": "ESNext", "module": "CommonJS",
"lib": ["ESNext", "DOM", "DOM.Iterable"], "lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "Node", "moduleResolution": "Node",
"sourceMap": true, "sourceMap": false,
"strict": false, "strict": false,
"noImplicitAny": true, "noImplicitAny": true,
"noUnusedLocals": false, "noUnusedLocals": false,
@ -28,10 +27,6 @@
] ]
} }
}, },
"include": [
"src/**/*",
"types/*"
],
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {
"module": "CommonJS" "module": "CommonJS"

5
types/globals.d.ts vendored
View File

@ -1,5 +0,0 @@
export {}
declare global {
const __static: string; // https://webpack.electron.build/using-static-assets
}

32
webpack.dll.ts Executable file
View File

@ -0,0 +1,32 @@
import path from "path";
import webpack from "webpack";
import { isDevelopment, outDir } from "./src/common/vars";
export const libName = "dll"
export const manifestPath = path.resolve(outDir, `${libName}.manifest.json`);
export const externalPackages = [
"react", "react-dom",
"ace-builds", "xterm",
"moment",
];
export default function (): webpack.Configuration {
return {
mode: isDevelopment ? "development" : "production",
cache: isDevelopment,
entry: {
[libName]: externalPackages
},
output: {
library: libName,
libraryTarget: "commonjs"
},
plugins: [
new webpack.DllPlugin({
name: libName,
path: manifestPath,
})
],
}
}

37
webpack.main.ts Executable file
View File

@ -0,0 +1,37 @@
import path from "path";
import webpack from "webpack";
import { isProduction, mainDir, outDir } from "./src/common/vars";
export default function (): webpack.Configuration {
return {
target: "electron-main",
mode: isProduction ? "production" : "development",
entry: {
main: path.resolve(mainDir, "index.ts"),
},
output: {
path: outDir,
},
resolve: {
extensions: ['.json', '.js', '.ts']
},
externals: [
"@kubernetes/client-node",
"handlebars",
"node-pty",
"ws",
],
module: {
rules: [
{
test: /\.node$/,
use: "node-loader"
},
{
test: /\.ts?$/,
use: "ts-loader",
},
]
},
}
}

134
webpack.renderer.ts Executable file
View File

@ -0,0 +1,134 @@
import path from "path";
import webpack from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import TerserWebpackPlugin from "terser-webpack-plugin";
import { isDevelopment, isProduction, outDir, rendererDir } from "./src/common/vars";
import { manifestPath, externalPackages } from "./webpack.dll";
export default function (): webpack.Configuration {
const tsConfigFile = path.resolve("./tsconfig.json");
const htmlTemplate = path.resolve(rendererDir, "template.html");
const sassCommonVars = path.resolve(rendererDir, "components/vars.scss");
return {
target: "electron-renderer",
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "cheap-eval-source-map",
cache: isDevelopment,
externals: externalPackages,
entry: {
renderer: path.resolve(rendererDir, "index.tsx"),
// renderer_vue: path.resolve(rendererDir, "_vue/index.js"),
},
output: {
path: outDir,
publicPath: '/',
filename: '[name].js',
chunkFilename: 'chunks/[name].js',
},
resolve: {
extensions: [
'.js', '.jsx', '.json',
'.ts', '.tsx', '.vue'
]
},
optimization: {
minimize: false,
minimizer: [
new TerserWebpackPlugin({
cache: true,
parallel: true,
sourceMap: true,
extractComments: {
condition: "some",
banner: [
`Lens - The Kubernetes IDE. Copyright ${new Date().getFullYear()} by Lakend Labs, Inc. All rights reserved.`
].join("\n")
}
})
],
},
module: {
rules: [
{
test: /\.node$/,
use: "node-loader"
},
{
test: /\.tsx?$/,
use: [
"babel-loader",
{
loader: "ts-loader",
options: {
transpileOnly: false,
appendTsSuffixTo: [/\.vue$/], // todo: remove after migration vue parts
configFile: tsConfigFile,
compilerOptions: {
// localization support
// https://lingui.js.org/guides/typescript.html
jsx: "preserve",
target: "es2016",
},
}
}
]
},
{
test: /\.(jpg|png|svg|map|ico)$/,
use: 'file-loader?name=assets/[name]-[hash:6].[ext]'
},
{
test: /\.(ttf|eot|woff2?)$/,
use: 'file-loader?name=fonts/[name].[ext]'
},
{
test: /\.s?css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
{
loader: "css-loader",
options: {
sourceMap: !isProduction
},
},
{
loader: "sass-loader",
options: {
sourceMap: !isProduction,
prependData: `@import "${path.basename(sassCommonVars)}";`,
sassOptions: {
includePaths: [
path.dirname(sassCommonVars)
]
},
}
},
]
}
]
},
plugins: [
...(isDevelopment ? [
new webpack.HotModuleReplacementPlugin()
] : []),
// provide access to external libraries, e.g. react, moment, etc.
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require(manifestPath),
}),
new HtmlWebpackPlugin({
template: htmlTemplate,
inject: true,
}),
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
}
}

1350
yarn.lock

File diff suppressed because it is too large Load Diff