diff --git a/.eslintrc.js b/.eslintrc.js index fad2b04a6a..3fd52c2465 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,6 +4,7 @@ module.exports = { ignorePatterns: [ "**/node_modules/**/*", "**/dist/**/*", + "**/static/**/*", ], settings: { react: { diff --git a/extensions/example-extension/package-lock.json b/extensions/example-extension/package-lock.json index 6ab5142f50..cf3390a42b 100644 --- a/extensions/example-extension/package-lock.json +++ b/extensions/example-extension/package-lock.json @@ -1,5 +1,5 @@ { - "name": "extension-example", + "name": "example-extension", "version": "1.0.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index 308e6383ee..086f0f5fe4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "download:kubectl": "yarn run ts-node build/download_kubectl.ts", "download:helm": "yarn run ts-node build/download_helm.ts", "build:tray-icons": "yarn run ts-node build/build_tray_icon.ts", - "lint": "yarn run eslint $@ --ext js,ts,tsx --max-warnings=0 src/ integration/ __mocks__/ build/ extensions/", + "lint": "yarn run eslint $@ --ext js,ts,tsx --max-warnings=0 .", "lint:fix": "yarn run lint --fix", "mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", "verify-docs": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict", diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index d2eec85a79..06d4feb23d 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -9,7 +9,7 @@ jest.mock( () => ({ ipcRenderer: { invoke: jest.fn(async (channel: string) => { - if (channel === "extensions:loaded") { + if (channel === "extensions:main") { return [ [ manifestPath, @@ -44,7 +44,7 @@ jest.mock( }), on: jest.fn( (channel: string, listener: (event: any, ...args: any[]) => void) => { - if (channel === "extensions:loaded") { + if (channel === "extensions:main") { // First initialize with extensions 1 and 2 // and then broadcast event to remove extensioin 2 and add extension number 3 setTimeout(() => { diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index 71eaa19524..30ef1157ec 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -1,5 +1,6 @@ import { app, ipcRenderer, remote } from "electron"; import { EventEmitter } from "events"; +import { isEqual } from "lodash"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import path from "path"; import { getHostedCluster } from "../common/cluster-store"; @@ -25,7 +26,12 @@ const logModule = "[EXTENSIONS-LOADER]"; export class ExtensionLoader { protected extensions = observable.map(); protected instances = observable.map(); - protected readonly requestExtensionsChannel = "extensions:loaded"; + + // IPC channel to broadcast changes to extensions from main + protected static readonly extensionsMainChannel = "extensions:main"; + + // IPC channel to broadcast changes to extensions from renderer + protected static readonly extensionsRendererChannel = "extensions:renderer"; // emits event "remove" of type LensExtension when the extension is removed private events = new EventEmitter(); @@ -95,28 +101,27 @@ export class ExtensionLoader { this.loadOnMain(); this.broadcastExtensions(); - reaction(() => this.extensions.toJS(), () => { + reaction(() => this.toJSON(), () => { this.broadcastExtensions(); }); - handleRequest(this.requestExtensionsChannel, () => { + handleRequest(ExtensionLoader.extensionsMainChannel, () => { return Array.from(this.toJSON()); }); + + subscribeToBroadcast(ExtensionLoader.extensionsRendererChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { + this.syncExtensions(extensions); + }); } protected async initRenderer() { const extensionListHandler = (extensions: [LensExtensionId, InstalledExtension][]) => { this.isLoaded = true; + this.syncExtensions(extensions); + const receivedExtensionIds = extensions.map(([lensExtensionId]) => lensExtensionId); - - // Add new extensions - extensions.forEach(([extId, ext]) => { - if (!this.extensions.has(extId)) { - this.extensions.set(extId, ext); - } - }); - - // Remove deleted extensions + + // Remove deleted extensions in renderer side only this.extensions.forEach((_, lensExtensionId) => { if (!receivedExtensionIds.includes(lensExtensionId)) { this.removeExtension(lensExtensionId); @@ -124,14 +129,26 @@ export class ExtensionLoader { }); }; - requestMain(this.requestExtensionsChannel).then(extensionListHandler); - subscribeToBroadcast(this.requestExtensionsChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { + reaction(() => this.toJSON(), () => { + this.broadcastExtensions(false); + }); + + requestMain(ExtensionLoader.extensionsMainChannel).then(extensionListHandler); + subscribeToBroadcast(ExtensionLoader.extensionsMainChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { extensionListHandler(extensions); }); } + syncExtensions(extensions: [LensExtensionId, InstalledExtension][]) { + extensions.forEach(([lensExtensionId, extension]) => { + if (!isEqual(this.extensions.get(lensExtensionId), extension)) { + this.extensions.set(lensExtensionId, extension); + } + }); + } + loadOnMain() { - logger.info(`${logModule}: load on main`); + logger.debug(`${logModule}: load on main`); this.autoInitExtensions(async (extension: LensMainExtension) => { // Each .add returns a function to remove the item const removeItems = [ @@ -151,7 +168,7 @@ export class ExtensionLoader { } loadOnClusterManagerRenderer() { - logger.info(`${logModule}: load on main renderer (cluster manager)`); + logger.debug(`${logModule}: load on main renderer (cluster manager)`); this.autoInitExtensions(async (extension: LensRendererExtension) => { const removeItems = [ registries.globalPageRegistry.add(extension.globalPages, extension), @@ -174,7 +191,7 @@ export class ExtensionLoader { } loadOnClusterRenderer() { - logger.info(`${logModule}: load on cluster renderer (dashboard)`); + logger.debug(`${logModule}: load on cluster renderer (dashboard)`); const cluster = getHostedCluster(); this.autoInitExtensions(async (extension: LensRendererExtension) => { @@ -204,26 +221,26 @@ export class ExtensionLoader { protected autoInitExtensions(register: (ext: LensExtension) => Promise) { return reaction(() => this.toJSON(), installedExtensions => { - for (const [extId, ext] of installedExtensions) { + for (const [extId, extension] of installedExtensions) { const alreadyInit = this.instances.has(extId); - if (ext.isEnabled && !alreadyInit) { + if (extension.isEnabled && !alreadyInit) { try { - const LensExtensionClass = this.requireExtension(ext); + const LensExtensionClass = this.requireExtension(extension); if (!LensExtensionClass) { continue; } - const instance = new LensExtensionClass(ext); + const instance = new LensExtensionClass(extension); instance.whenEnabled(() => register(instance)); instance.enable(); this.instances.set(extId, instance); } catch (err) { - logger.error(`${logModule}: activation extension error`, { ext, err }); + logger.error(`${logModule}: activation extension error`, { ext: extension, err }); } - } else if (!ext.isEnabled && alreadyInit) { + } else if (!extension.isEnabled && alreadyInit) { this.removeInstance(extId); } } @@ -262,8 +279,8 @@ export class ExtensionLoader { }); } - broadcastExtensions() { - broadcastMessage(this.requestExtensionsChannel, Array.from(this.toJSON())); + broadcastExtensions(main = true) { + broadcastMessage(main ? ExtensionLoader.extensionsMainChannel : ExtensionLoader.extensionsRendererChannel, Array.from(this.toJSON())); } } diff --git a/src/extensions/extensions-store.ts b/src/extensions/extensions-store.ts index 1533c9ad89..07edb20453 100644 --- a/src/extensions/extensions-store.ts +++ b/src/extensions/extensions-store.ts @@ -45,17 +45,6 @@ export class ExtensionsStore extends BaseStore { await extensionLoader.whenLoaded; await this.whenLoaded; - // apply state on changes from store - reaction(() => this.state.toJS(), extensionsState => { - extensionsState.forEach((state, extId) => { - const ext = extensionLoader.getExtension(extId); - - if (ext && !ext.isBundled) { - ext.isEnabled = state.enabled; - } - }); - }); - // save state on change `extension.isEnabled` reaction(() => this.getState(extensionLoader), extensionsState => { this.state.merge(extensionsState); @@ -65,7 +54,9 @@ export class ExtensionsStore extends BaseStore { isEnabled(extId: LensExtensionId) { const state = this.state.get(extId); - return state && state.enabled; // by default false + // By default false, so that copied extensions are disabled by default. + // If user installs the extension from the UI, the Extensions component will specifically enable it. + return Boolean(state?.enabled); } @action diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index 83ec7e27cd..903d30159f 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -62,6 +62,9 @@ export class Extensions extends React.Component { @observable search = ""; @observable installPath = ""; + // True if the preliminary install steps have started, but unpackExtension has not started yet + @observable startingInstall = false; + /** * Extensions that were removed from extensions but are still in "uninstalling" state */ @@ -91,11 +94,20 @@ export class Extensions extends React.Component { }); this.addedInstalling.forEach(({ id, displayName }) => { + const extension = this.extensions.find(extension => extension.id === id); + + if (!extension) { + throw new Error("Extension not found"); + } + Notifications.ok(

Extension {displayName} successfully installed!

); this.extensionState.delete(id); this.installPath = ""; + + // Enable installed extensions by default. + extension.isEnabled = true; }); }) ); @@ -152,6 +164,8 @@ export class Extensions extends React.Component { const { installPath } = this; if (!installPath) return; + + this.startingInstall = true; const fileName = path.basename(installPath); try { @@ -161,13 +175,14 @@ export class Extensions extends React.Component { const { promise: filePromise } = downloadFile({ url: installPath, timeout: 60000 /*1m*/ }); const data = await filePromise; - this.requestInstall({ fileName, data }); + await this.requestInstall({ fileName, data }); } // otherwise installing from system path else if (InputValidators.isPath.validate(installPath)) { - this.requestInstall({ fileName, filePath: installPath }); + await this.requestInstall({ fileName, filePath: installPath }); } } catch (error) { + this.startingInstall = false; Notifications.error(

Installation has failed: {String(error)}

); @@ -186,11 +201,11 @@ export class Extensions extends React.Component { }; async preloadExtensions(requests: InstallRequest[], { showError = true } = {}) { - const preloadedRequests = requests.filter(req => req.data); + const preloadedRequests = requests.filter(request => request.data); await Promise.all( requests - .filter(req => !req.data && req.filePath) + .filter(request => !request.data && request.filePath) .map(async request => { try { const data = await fse.readFile(request.filePath); @@ -247,11 +262,11 @@ export class Extensions extends React.Component { // copy files to temp await fse.ensureDir(this.getExtensionPackageTemp()); - requests.forEach(req => { - const tempFile = this.getExtensionPackageTemp(req.fileName); + for (const request of requests) { + const tempFile = this.getExtensionPackageTemp(request.fileName); - fse.writeFileSync(tempFile, req.data); - }); + await fse.writeFile(tempFile, request.data); + } // validate packages await Promise.all( @@ -289,15 +304,24 @@ export class Extensions extends React.Component { const preloadedRequests = await this.preloadExtensions(requests); const validatedRequests = await this.createTempFilesAndValidate(preloadedRequests); - validatedRequests.forEach(install => { + // If there are no requests for installing, reset startingInstall state + if (validatedRequests.length === 0) { + this.startingInstall = false; + } + + for (const install of validatedRequests) { const { name, version, description } = install.manifest; const extensionFolder = this.getExtensionDestFolder(name); - const folderExists = fse.existsSync(extensionFolder); - + const folderExists = await fse.pathExists(extensionFolder); + if (!folderExists) { // auto-install extension if not yet exists this.unpackExtension(install); } else { + // If we show the confirmation dialog, we stop the install spinner until user clicks ok + // and the install continues + this.startingInstall = false; + // otherwise confirmation required (re-install / update) const removeNotification = Notifications.info(
@@ -315,21 +339,23 @@ export class Extensions extends React.Component {
); } - }); + } } async unpackExtension({ fileName, tempFile, manifest: { name, version } }: InstallRequestValidated) { const displayName = extensionDisplayName(name, version); - const extensionFolder = this.getExtensionDestFolder(name); - const unpackingTempFolder = path.join(path.dirname(tempFile), `${path.basename(tempFile)}-unpacked`); const extensionId = path.join(extensionDiscovery.nodeModulesPath, name, "package.json"); - logger.info(`Unpacking extension ${displayName}`, { fileName, tempFile }); - this.extensionState.set(extensionId, { state: "installing", displayName }); + this.startingInstall = false; + + const extensionFolder = this.getExtensionDestFolder(name); + const unpackingTempFolder = path.join(path.dirname(tempFile), `${path.basename(tempFile)}-unpacked`); + + logger.info(`Unpacking extension ${displayName}`, { fileName, tempFile }); try { // extract to temp folder first @@ -455,7 +481,7 @@ export class Extensions extends React.Component { * True if at least one extension is in installing state */ @computed get isInstalling() { - return [...this.extensionState.values()].some(extension => extension.state === "installing"); + return this.startingInstall || [...this.extensionState.values()].some(extension => extension.state === "installing"); } render() { diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx new file mode 100644 index 0000000000..6578f4ac20 --- /dev/null +++ b/src/renderer/components/cluster-manager/bottom-bar.test.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import "@testing-library/jest-dom/extend-expect"; + +import { BottomBar } from "./bottom-bar"; +jest.mock("../../../extensions/registries"); +import { statusBarRegistry } from "../../../extensions/registries"; + +describe("", () => { + + it("renders w/o errors", () => { + const { container } = render(); + + expect(container).toBeInstanceOf(HTMLElement); + }); + + // some defensive testing + it("renders w/o errors when .getItems() returns edge cases", async () => { + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => undefined); + expect(() => render()).not.toThrow(); + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => null); + expect(() => render()).not.toThrow(); + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => []); + expect(() => render()).not.toThrow(); + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => { return {};}); + expect(() => render()).not.toThrow(); + }); + + it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", async () => { + const testId = "testId"; + const text = "heee"; + + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => [ + { item: {text} } + ]); + const { getByTestId } = render(); + + expect(await getByTestId(testId)).toHaveTextContent(text); + }); + + it("renders items [{item: () => React.ReactNode}] (4.0.0-rc.1+)", async () => { + const testId = "testId"; + const text = "heee"; + + statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => [ + { item: () => {text} } + ]); + const { getByTestId } = render(); + + expect(await getByTestId(testId)).toHaveTextContent(text); + }); +}); diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index c70c25aeb9..489d90769f 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -11,6 +11,8 @@ import { statusBarRegistry } from "../../../extensions/registries"; export class BottomBar extends React.Component { render() { const { currentWorkspace } = workspaceStore; + // in case .getItems() returns undefined + const items = statusBarRegistry.getItems() ?? []; return (
@@ -22,10 +24,17 @@ export class BottomBar extends React.Component { htmlFor="current-workspace" />
- {statusBarRegistry.getItems().map(({ item }, index) => { + {Array.isArray(items) && items.map(({ item }, index) => { if (!item) return; - return
{item}
; + return ( +
+ {typeof item === "function" ? item() : item} +
+ ); })}
diff --git a/types/dom.d.ts b/types/dom.d.ts index 61e94a1aa5..40926b249b 100644 --- a/types/dom.d.ts +++ b/types/dom.d.ts @@ -1,7 +1,7 @@ -export {} +export {}; declare global { interface Element { scrollIntoViewIfNeeded(opt_center?: boolean): void; } -} \ No newline at end of file +} diff --git a/types/font-face.d.ts b/types/font-face.d.ts index cb1d3e84f4..ca4282ae97 100644 --- a/types/font-face.d.ts +++ b/types/font-face.d.ts @@ -1,6 +1,6 @@ // https://www.w3.org/TR/css-font-loading/ // https://developer.mozilla.org/en-US/docs/Web/API/FontFace -export {} +export {}; declare global { const FontFace: FontFace; @@ -10,11 +10,11 @@ declare global { } type CSSOMString = string; - type FontFaceLoadStatus = 'unloaded' | 'loading' | 'loaded' | 'error'; - type FontFaceSetStatus = 'loading' | 'loaded'; + type FontFaceLoadStatus = "unloaded" | "loading" | "loaded" | "error"; + type FontFaceSetStatus = "loading" | "loaded"; - interface FontFace extends FontFaceDescriptors { - new(family: string, source: string | ArrayBuffer, descriptors?: FontFaceDescriptors): FontFace; + class FontFace implements FontFaceDescriptors { + constructor(family: string, source: string | ArrayBuffer, descriptors?: FontFaceDescriptors); readonly status: FontFaceLoadStatus; readonly loaded: Promise; variationSettings: CSSOMString; @@ -41,4 +41,4 @@ declare global { delete(font: FontFace): void; clear(): void; } -} \ No newline at end of file +} diff --git a/webpack.extensions.ts b/webpack.extensions.ts index f3adcc858e..b88dfde7eb 100644 --- a/webpack.extensions.ts +++ b/webpack.extensions.ts @@ -1,87 +1,89 @@ -import path from 'path'; +import path from "path"; import webpack from "webpack"; import { sassCommonVars } from "./src/common/vars"; export default function (): webpack.Configuration { - const entry = "./src/extensions/extension-api.ts" - const outDir = "./src/extensions/npm/extensions/dist"; - return { - // Compile for Electron for renderer process - // see - target: "electron-renderer", - entry, - output: { - filename: 'extension-api.js', - // need to be an absolute path - path: path.resolve(__dirname, `${outDir}/src/extensions`), - // can be use in commonjs environments - // e.g. require('@k8slens/extensions') - libraryTarget: "commonjs" + const entry = "./src/extensions/extension-api.ts"; + const outDir = "./src/extensions/npm/extensions/dist"; + return { + // Compile for Electron for renderer process + // see + target: "electron-renderer", + entry, + // this is the default mode, so we should make it explicit to silence the warning + mode: "production", + output: { + filename: "extension-api.js", + // need to be an absolute path + path: path.resolve(__dirname, `${outDir}/src/extensions`), + // can be use in commonjs environments + // e.g. require('@k8slens/extensions') + libraryTarget: "commonjs" + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: "ts-loader", + options: { + // !! ts-loader will use tsconfig.json at folder root + // !! changes in tsconfig.json may have side effects + // !! on '@k8slens/extensions' module + compilerOptions: { + declaration: true, // output .d.ts + sourceMap: false, // to override sourceMap: true in tsconfig.json + outDir // where the .d.ts should be located + } + } }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: 'ts-loader', - options: { - // !! ts-loader will use tsconfig.json at folder root - // !! changes in tsconfig.json may have side effects - // !! on '@k8slens/extensions' module - compilerOptions: { - declaration: true, // output .d.ts - sourceMap: false, // to override sourceMap: true in tsconfig.json - outDir // where the .d.ts should be located - } - } + // for src/renderer/components/fonts/roboto-mono-nerd.ttf + // in src/renderer/components/dock/terminal.ts 95:25-65 + { + test: /\.(ttf|eot|woff2?)$/, + use: { + loader: "url-loader", + options: { + name: "fonts/[name].[ext]" + } + } + }, + // for import scss files + { + test: /\.s?css$/, + use: [ + // creates `style` nodes from JS strings + "style-loader", + // translates CSS into CommonJS + "css-loader", + { + loader: "sass-loader", + options: { + prependData: `@import "${path.basename(sassCommonVars)}";`, + sassOptions: { + includePaths: [ + path.dirname(sassCommonVars) + ] }, - // for src/renderer/components/fonts/roboto-mono-nerd.ttf - // in src/renderer/components/dock/terminal.ts 95:25-65 - { - test: /\.(ttf|eot|woff2?)$/, - use: { - loader: "url-loader", - options: { - name: "fonts/[name].[ext]" - } - } - }, - // for import scss files - { - test: /\.s?css$/, - use: [ - // creates `style` nodes from JS strings - "style-loader", - // translates CSS into CommonJS - "css-loader", - { - loader: "sass-loader", - options: { - prependData: `@import "${path.basename(sassCommonVars)}";`, - sassOptions: { - includePaths: [ - path.dirname(sassCommonVars) - ] - }, - } - }, - ] - } - ] - }, - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - plugins: [ - // In ts-loader's README they said to output a built .d.ts file, - // you can set "declaration": true in tsconfig.extensions.json, - // and use the DeclarationBundlerPlugin in your webpack config... but - // !! the DeclarationBundlerPlugin doesn't work anymore, author archived it. - // https://www.npmjs.com/package/declaration-bundler-webpack-plugin - // new DeclarationBundlerPlugin({ - // moduleName: '@k8slens/extensions', - // out: 'extension-api.d.ts', - // }) - ] - }; + } + }, + ] + } + ] + }, + resolve: { + extensions: [".ts", ".tsx", ".js"] + }, + plugins: [ + // In ts-loader's README they said to output a built .d.ts file, + // you can set "declaration": true in tsconfig.extensions.json, + // and use the DeclarationBundlerPlugin in your webpack config... but + // !! the DeclarationBundlerPlugin doesn't work anymore, author archived it. + // https://www.npmjs.com/package/declaration-bundler-webpack-plugin + // new DeclarationBundlerPlugin({ + // moduleName: '@k8slens/extensions', + // out: 'extension-api.d.ts', + // }) + ] + }; } diff --git a/webpack.main.ts b/webpack.main.ts index c388466cdc..8d83d2b75d 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -1,12 +1,13 @@ import path from "path"; import webpack from "webpack"; -import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin" +import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"; import { isDevelopment, isProduction, mainDir, buildDir } from "./src/common/vars"; import nodeExternals from "webpack-node-externals"; import ProgressBarPlugin from "progress-bar-webpack-plugin"; +import * as vars from "./src/common/vars"; export default function (): webpack.Configuration { - console.info('WEBPACK:main', require("./src/common/vars")) + console.info("WEBPACK:main", vars); return { context: __dirname, target: "electron-main", @@ -21,7 +22,7 @@ export default function (): webpack.Configuration { path: buildDir, }, resolve: { - extensions: ['.json', '.js', '.ts'] + extensions: [".json", ".js", ".ts"] }, externals: [ nodeExternals() @@ -48,5 +49,5 @@ export default function (): webpack.Configuration { new ProgressBarPlugin(), new ForkTsCheckerPlugin(), ].filter(Boolean) - } + }; } diff --git a/webpack.renderer.ts b/webpack.renderer.ts index 62adc31bb5..f788ff40c3 100755 --- a/webpack.renderer.ts +++ b/webpack.renderer.ts @@ -4,17 +4,18 @@ import webpack from "webpack"; import HtmlWebpackPlugin from "html-webpack-plugin"; import MiniCssExtractPlugin from "mini-css-extract-plugin"; import TerserPlugin from "terser-webpack-plugin"; -import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin" +import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"; import ProgressBarPlugin from "progress-bar-webpack-plugin"; -import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' +import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"; +import * as vars from "./src/common/vars"; export default [ webpackLensRenderer -] +]; export function webpackLensRenderer({ showVars = true } = {}): webpack.Configuration { if (showVars) { - console.info('WEBPACK:renderer', require("./src/common/vars")); + console.info("WEBPACK:renderer", vars); } return { context: __dirname, @@ -27,7 +28,7 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura hot: true, // to avoid cors errors when requests is from iframes disableHostCheck: true, - headers: { 'Access-Control-Allow-Origin': '*' }, + headers: { "Access-Control-Allow-Origin": "*" }, }, name: "lens-app", mode: isProduction ? "production" : "development", @@ -39,10 +40,10 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura libraryTarget: "global", library: "", globalObject: "this", - publicPath: publicPath, + publicPath, path: buildDir, - filename: '[name].js', - chunkFilename: 'chunks/[name].js', + filename: "[name].js", + chunkFilename: "chunks/[name].js", }, stats: { warningsFilter: [ @@ -51,8 +52,8 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura }, resolve: { extensions: [ - '.js', '.jsx', '.json', - '.ts', '.tsx', + ".js", ".jsx", ".json", + ".ts", ".tsx", ] }, optimization: { @@ -91,7 +92,7 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura }], ], plugins: [ - isDevelopment && require.resolve('react-refresh/babel'), + isDevelopment && require.resolve("react-refresh/babel"), ].filter(Boolean), } }, @@ -190,5 +191,5 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura isDevelopment && new ReactRefreshWebpackPlugin(), ].filter(Boolean), - } + }; }