upgrade vite to v3 (#5417)

* update type-fest imports

* move main css to html

* update electron imports

* update nunjucks imports

* use swagger ui dist

* remove commonjs-externals and add electron node require plugin

* update package

* fix misc.ts imports

* remove buffer from builtins since we use a package for it

* plugin docs

* Update packages/insomnia/src/main/window-utils.ts

Co-authored-by: Filipe Freire <livrofubia@gmail.com>
This commit is contained in:
James Gatz 2022-11-17 13:37:53 +01:00 committed by GitHub
parent be8fa82a74
commit 7988137f2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 644 additions and 2776 deletions

View File

@ -1,4 +1,4 @@
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
// HTTP version codes // HTTP version codes
export const HttpVersions = { export const HttpVersions = {

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,7 @@
"start:dev-server": "vite dev", "start:dev-server": "vite dev",
"start:electron": "cross-env NODE_ENV=development esr esbuild.main.ts && electron .", "start:electron": "cross-env NODE_ENV=development esr esbuild.main.ts && electron .",
"test": "jest", "test": "jest",
"electron:dev-build": "electron ./build/main.min.js",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"type-check": "tsc --noEmit --project tsconfig.build.json", "type-check": "tsc --noEmit --project tsconfig.build.json",
"type-check:watch": "npm run type-check -- --watch", "type-check:watch": "npm run type-check -- --watch",
@ -54,7 +55,6 @@
"axios": "^0.21.2", "axios": "^0.21.2",
"clone": "^2.1.0", "clone": "^2.1.0",
"color": "^3.1.2", "color": "^3.1.2",
"crypto-browserify": "^3.12.0",
"dompurify": "^2.3.6", "dompurify": "^2.3.6",
"electron-context-menu": "^3.1.1", "electron-context-menu": "^3.1.1",
"electron-log": "^4.4.3", "electron-log": "^4.4.3",
@ -89,6 +89,7 @@
"jshint": "^2.11.1", "jshint": "^2.11.1",
"jsonlint-mod-fixed": "1.7.7", "jsonlint-mod-fixed": "1.7.7",
"jsonpath-plus": "^6.0.1", "jsonpath-plus": "^6.0.1",
"jwt-authentication": "^0.4.0",
"marked": "^4.0.10", "marked": "^4.0.10",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
@ -142,7 +143,7 @@
"@types/redux-mock-store": "^1.0.2", "@types/redux-mock-store": "^1.0.2",
"@types/rimraf": "^3.0.2", "@types/rimraf": "^3.0.2",
"@types/styled-components": "^5.1.23", "@types/styled-components": "^5.1.23",
"@types/swagger-ui-react": "^4.11.0", "@types/swagger-ui-dist": "^3.30.1",
"@types/tough-cookie": "^2.3.7", "@types/tough-cookie": "^2.3.7",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@types/vkbeautify": "^0.99.2", "@types/vkbeautify": "^0.99.2",
@ -163,9 +164,9 @@
"electron-builder-squirrel-windows": "23.0.7", "electron-builder-squirrel-windows": "23.0.7",
"electron-devtools-installer": "^3.2.0", "electron-devtools-installer": "^3.2.0",
"electron-notarize": "^1.1.1", "electron-notarize": "^1.1.1",
"esbuild": "^0.14.27", "esbuild": "^0.15.13",
"esbuild-plugin-alias": "0.2.1", "esbuild-plugin-alias": "0.2.1",
"esbuild-runner": "^2.2.1", "esbuild-runner": "^2.2.2",
"fuzzysort": "^1.2.1", "fuzzysort": "^1.2.1",
"graphql": "^16.3.0", "graphql": "^16.3.0",
"graphql-language-service": "^4.1.5", "graphql-language-service": "^4.1.5",
@ -174,7 +175,6 @@
"jest-environment-jsdom": "^28.0.2", "jest-environment-jsdom": "^28.0.2",
"jest-mock": "^28.0.2", "jest-mock": "^28.0.2",
"json-order": "^1.1.0", "json-order": "^1.1.0",
"jwt-authentication": "^0.4.0",
"less": "^3.8.1", "less": "^3.8.1",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"ncp": "^2.0.0", "ncp": "^2.0.0",
@ -194,16 +194,15 @@
"reselect": "^4.1.5", "reselect": "^4.1.5",
"srp-js": "^0.2.1", "srp-js": "^0.2.1",
"styled-components": "^5.3.3", "styled-components": "^5.3.3",
"swagger-ui-react": "4.15.0", "swagger-ui-dist": "^4.15.5",
"tinykeys": "^1.4.0", "tinykeys": "^1.4.0",
"type-fest": "^2.12.0", "type-fest": "^2.12.0",
"typescript": "^4.5.5", "typescript": "^4.5.5",
"vite": "^2.8.6", "vite": "^3.2.3",
"vite-plugin-commonjs-externals": "^0.1.1",
"vkbeautify": "^0.99.1", "vkbeautify": "^0.99.1",
"ws": "^8.8.1",
"xmldom": "^0.5.0", "xmldom": "^0.5.0",
"xpath": "0.0.32", "xpath": "0.0.32"
"ws": "^8.8.1"
}, },
"dev": { "dev": {
"dev-server-port": 3334 "dev-server-port": 3334

View File

@ -1,4 +1,4 @@
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
export const GrpcRequestEventEnum = { export const GrpcRequestEventEnum = {
start: 'GRPC_START', start: 'GRPC_START',

View File

@ -1,4 +1,4 @@
import { sanitize } from 'dompurify'; import dompurify from 'dompurify';
import { marked } from 'marked'; import { marked } from 'marked';
marked.setOptions({ marked.setOptions({
@ -10,4 +10,4 @@ marked.setOptions({
smartypants: false, smartypants: false,
}); });
export const markdownToHTML = (input: string) => sanitize(marked.parse(input)); export const markdownToHTML = (input: string) => dompurify.sanitize(marked.parse(input));

View File

@ -1,3 +1,4 @@
/// <reference types="vite/client" />
import type { MainBridgeAPI } from './main/ipc/main'; import type { MainBridgeAPI } from './main/ipc/main';
declare global { declare global {

View File

@ -5,6 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" <meta http-equiv="Content-Security-Policy"
content="font-src 'self' data:; connect-src * data:; default-src * insomnia://*; img-src blob: data: * insomnia://*; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src blob: data: mediastream: * insomnia://*;" /> content="font-src 'self' data:; connect-src * data:; default-src * insomnia://*; img-src blob: data: * insomnia://*; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src blob: data: mediastream: * insomnia://*;" />
<link rel="stylesheet" href="./ui/css/index.less" />
</head> </head>
<body> <body>

View File

@ -1,5 +1,5 @@
import electron, { app, ipcMain, session } from 'electron'; import electron, { app, ipcMain, session } from 'electron';
import { BrowserWindow } from 'electron/main'; import { BrowserWindow } from 'electron';
import contextMenu from 'electron-context-menu'; import contextMenu from 'electron-context-menu';
import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electron-devtools-installer'; import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electron-devtools-installer';
import path from 'path'; import path from 'path';
@ -224,7 +224,6 @@ async function _trackStats() {
return; return;
} }
const { BrowserWindow } = electron;
const notification: ToastNotification = { const notification: ToastNotification = {
key: `updated-${currentVersion}`, key: `updated-${currentVersion}`,
url: changelogUrl(), url: changelogUrl(),

View File

@ -1,4 +1,4 @@
import electron, { BrowserWindow, MenuItemConstructorOptions } from 'electron'; import electron, { type BrowserWindow as ElectronBrowserWindow, type MenuItemConstructorOptions } from 'electron';
import fs from 'fs'; import fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import path from 'path'; import path from 'path';
@ -19,14 +19,14 @@ import { clickLink, getDataDirectory } from '../common/electron-helpers';
import * as log from '../common/log'; import * as log from '../common/log';
import LocalStorage from './local-storage'; import LocalStorage from './local-storage';
const { app, Menu, shell, dialog, clipboard } = electron; const { app, Menu, shell, dialog, clipboard, BrowserWindow } = electron;
const DEFAULT_WIDTH = 1280; const DEFAULT_WIDTH = 1280;
const DEFAULT_HEIGHT = 720; const DEFAULT_HEIGHT = 720;
const MINIMUM_WIDTH = 500; const MINIMUM_WIDTH = 500;
const MINIMUM_HEIGHT = 400; const MINIMUM_HEIGHT = 400;
let mainWindow: BrowserWindow | null = null; let mainWindow: ElectronBrowserWindow | null = null;
let localStorage: LocalStorage | null = null; let localStorage: LocalStorage | null = null;
interface Bounds { interface Bounds {
@ -578,7 +578,7 @@ const getZoomFactor = () => {
}; };
export const setZoom = (transformer: (current: number) => number) => () => { export const setZoom = (transformer: (current: number) => number) => () => {
const browserWindow = electron.BrowserWindow.getFocusedWindow(); const browserWindow = BrowserWindow.getFocusedWindow();
if (!browserWindow || !browserWindow.webContents) { if (!browserWindow || !browserWindow.webContents) {
return; return;

View File

@ -2,7 +2,7 @@ import { readFileSync } from 'fs';
import { Settings } from 'insomnia-common'; import { Settings } from 'insomnia-common';
import { ErrorResult, INSOMNIA_CONFIG_FILENAME, InsomniaConfig, isErrorResult, validate } from 'insomnia-config'; import { ErrorResult, INSOMNIA_CONFIG_FILENAME, InsomniaConfig, isErrorResult, validate } from 'insomnia-config';
import { resolve } from 'path'; import { resolve } from 'path';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
import { isDevelopment } from '../../common/constants'; import { isDevelopment } from '../../common/constants';
import { getDataDirectory, getPortableExecutableDir } from '../../common/electron-helpers'; import { getDataDirectory, getPortableExecutableDir } from '../../common/electron-helpers';

View File

@ -1,4 +1,4 @@
import { Merge } from 'type-fest'; import type { Merge } from 'type-fest';
import { database as db } from '../common/database'; import { database as db } from '../common/database';
import { strings } from '../common/strings'; import { strings } from '../common/strings';

View File

@ -1,5 +1,5 @@
import { MethodDefinition } from '@grpc/grpc-js'; import { MethodDefinition } from '@grpc/grpc-js';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
// TODO(TSCONVERSION) remove this alias and type MethodDefinition correctly // TODO(TSCONVERSION) remove this alias and type MethodDefinition correctly
export type GrpcMethodDefinition = MethodDefinition<any, any>; export type GrpcMethodDefinition = MethodDefinition<any, any>;

View File

@ -1,4 +1,4 @@
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
export const GrpcStatusEnum = { export const GrpcStatusEnum = {
OK: 0, OK: 0,

View File

@ -1,4 +1,4 @@
import { BrowserWindow } from 'electron'; import electron from 'electron';
import querystring from 'querystring'; import querystring from 'querystring';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -81,7 +81,7 @@ export function authorizeUserInWindow({
} = await models.settings.getOrCreate(); } = await models.settings.getOrCreate();
// Create a child window // Create a child window
const child = new BrowserWindow({ const child = new electron.BrowserWindow({
webPreferences: { webPreferences: {
nodeIntegration: false, nodeIntegration: false,
partition: sessionId, partition: sessionId,

View File

@ -10,7 +10,7 @@ const EMPTY_ARG = '__EMPTY_NUNJUCKS_ARG__';
export default class BaseExtension { export default class BaseExtension {
_ext: PluginTemplateTag | null = null; _ext: PluginTemplateTag | null = null;
_plugin: Plugin | null = null; _plugin: Plugin | null = null;
tags: PluginTemplateTag['name'][] | null = null; tags: PluginTemplateTag['name'][] = [];
constructor(ext: PluginTemplateTag, plugin: Plugin) { constructor(ext: PluginTemplateTag, plugin: Plugin) {
this._ext = ext; this._ext = ext;
@ -30,7 +30,7 @@ export default class BaseExtension {
} }
getName() { getName() {
return this._ext?.displayName || this.getTag(); return typeof this._ext?.displayName === 'string' ? this._ext?.displayName : this.getTag();
} }
getDescription() { getDescription() {

View File

@ -1,7 +1,7 @@
import type { Request } from '../../models/request'; import type { Request } from '../../models/request';
import type { Response } from '../../models/response'; import type { Response } from '../../models/response';
import type { PluginStore } from '../../plugins/context'; import type { PluginStore } from '../../plugins/context';
import type { NunjucksParsedTagArg } from '../utils'; import type { NunjucksActionTag, NunjucksParsedTagArg } from '../utils';
export type PluginArgumentValue = string | number | boolean; export type PluginArgumentValue = string | number | boolean;
@ -87,12 +87,12 @@ export interface PluginTemplateTagAction {
} }
export interface PluginTemplateTag { export interface PluginTemplateTag {
args: PluginArgument[]; args: NunjucksParsedTagArg[];
name: string; name: string;
displayName: DisplayName; displayName: DisplayName;
disablePreview: () => boolean; disablePreview: () => boolean;
description: string; description: string;
actions: PluginTemplateTagAction[]; actions: NunjucksActionTag[];
run: (context: PluginTemplateTagContext, ...arg: any[]) => Promise<any> | any; run: (context: PluginTemplateTagContext, ...arg: any[]) => Promise<any> | any;
deprecated?: boolean; deprecated?: boolean;
validate?: (value: any) => string | null; validate?: (value: any) => string | null;

View File

@ -1,5 +1,5 @@
import { type Environment } from 'nunjucks'; import { type Environment } from 'nunjucks';
import * as nunjucks from 'nunjucks/browser/nunjucks'; import nunjucks from 'nunjucks/browser/nunjucks';
import type { TemplateTag } from '../plugins/index'; import type { TemplateTag } from '../plugins/index';
import * as plugins from '../plugins/index'; import * as plugins from '../plugins/index';
@ -26,10 +26,14 @@ export const RENDER_VARS = 'variables';
export const RENDER_TAGS = 'tags'; export const RENDER_TAGS = 'tags';
export const NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME = '_'; export const NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME = '_';
type NunjucksEnvironment = Environment & {
extensions: Record<string, BaseExtension>;
};
// Cached globals // Cached globals
let nunjucksVariablesOnly: Environment | null = null; let nunjucksVariablesOnly: NunjucksEnvironment | null = null;
let nunjucksTagsOnly: Environment | null = null; let nunjucksTagsOnly: NunjucksEnvironment | null = null;
let nunjucksAll: Environment | null = null; let nunjucksAll: NunjucksEnvironment | null = null;
/** /**
* Render text based on stuff * Render text based on stuff
@ -109,13 +113,14 @@ export function reload() {
*/ */
export async function getTagDefinitions() { export async function getTagDefinitions() {
const env = await getNunjucks(RENDER_ALL); const env = await getNunjucks(RENDER_ALL);
return Object.keys(env.extensions) return Object.keys(env.extensions)
.map(k => env.extensions[k]) .map(k => env.extensions[k])
.filter(ext => !ext.isDeprecated()) .filter(ext => !ext.isDeprecated())
.sort((a, b) => (a.getPriority() > b.getPriority() ? 1 : -1)) .sort((a, b) => (a.getPriority() > b.getPriority() ? 1 : -1))
.map<NunjucksParsedTag>(ext => ({ .map<NunjucksParsedTag>(ext => ({
name: ext.getTag(), name: ext.getTag() || '',
displayName: ext.getName(), displayName: ext.getName() || '',
liveDisplayName: ext.getLiveDisplayName(), liveDisplayName: ext.getLiveDisplayName(),
description: ext.getDescription(), description: ext.getDescription(),
disablePreview: ext.getDisablePreview(), disablePreview: ext.getDisablePreview(),
@ -124,7 +129,7 @@ export async function getTagDefinitions() {
})); }));
} }
async function getNunjucks(renderMode: string) { async function getNunjucks(renderMode: string): Promise<NunjucksEnvironment> {
if (renderMode === RENDER_VARS && nunjucksVariablesOnly) { if (renderMode === RENDER_VARS && nunjucksVariablesOnly) {
return nunjucksVariablesOnly; return nunjucksVariablesOnly;
} }
@ -170,7 +175,7 @@ async function getNunjucks(renderMode: string) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// Create Env with Extensions // // Create Env with Extensions //
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
const nj = nunjucks.configure(config); const nunjucksEnvironment = nunjucks.configure(config) as NunjucksEnvironment;
let allTemplateTagPlugins: TemplateTag[]; let allTemplateTagPlugins: TemplateTag[];
try { try {
@ -184,27 +189,27 @@ async function getNunjucks(renderMode: string) {
const allExtensions = allTemplateTagPlugins; const allExtensions = allTemplateTagPlugins;
for (let i = 0; i < allExtensions.length; i++) { for (const extension of allExtensions) {
const { templateTag, plugin } = allExtensions[i]; const { templateTag, plugin } = extension;
templateTag.priority = templateTag.priority || i * 100; templateTag.priority = templateTag.priority || allExtensions.indexOf(extension);
// @ts-expect-error -- TSCONVERSION // @ts-expect-error -- TSCONVERSION
const instance = new BaseExtension(templateTag, plugin); const instance = new BaseExtension(templateTag, plugin);
nj.addExtension(instance.getTag(), instance); nunjucksEnvironment.addExtension(instance.getTag() || '', instance);
// Hidden helper filter to debug complicated things // Hidden helper filter to debug complicated things
// eg. `{{ foo | urlencode | debug | upper }}` // eg. `{{ foo | urlencode | debug | upper }}`
nj.addFilter('debug', (o: any) => o); nunjucksEnvironment.addFilter('debug', (o: any) => o);
} }
// ~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~ //
// Cache Env and Return // // Cache Env and Return //
// ~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~ //
if (renderMode === RENDER_VARS) { if (renderMode === RENDER_VARS) {
nunjucksVariablesOnly = nj; nunjucksVariablesOnly = nunjucksEnvironment;
} else if (renderMode === RENDER_TAGS) { } else if (renderMode === RENDER_TAGS) {
nunjucksTagsOnly = nj; nunjucksTagsOnly = nunjucksEnvironment;
} else { } else {
nunjucksAll = nj; nunjucksAll = nunjucksEnvironment;
} }
return nj; return nunjucksEnvironment;
} }

View File

@ -1,6 +1,6 @@
import React, { Component, CSSProperties, NamedExoticComponent, ReactNode, SVGProps } from 'react'; import React, { Component, CSSProperties, NamedExoticComponent, ReactNode, SVGProps } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
import { SvgIcnArrowRight } from './assets/svgr/IcnArrowRight'; import { SvgIcnArrowRight } from './assets/svgr/IcnArrowRight';
import { SvgIcnBitbucketLogo } from './assets/svgr/IcnBitbucketLogo'; import { SvgIcnBitbucketLogo } from './assets/svgr/IcnBitbucketLogo';

View File

@ -0,0 +1,46 @@
import 'swagger-ui-dist/swagger-ui.css';
import React, { FC, useEffect, useRef } from 'react';
import { SwaggerConfigs, SwaggerUIBundle as createSwaggerUI } from 'swagger-ui-dist';
export const SwaggerUI: FC<SwaggerConfigs> = props => {
const swaggerUIRef = useRef<SwaggerConfigs | null>(null);
const domNodeRef = useRef(null);
useEffect(() => {
swaggerUIRef.current = createSwaggerUI({
...props,
domNode: domNodeRef.current,
});
}, [props]);
useEffect(() => {
const swaggerUI = swaggerUIRef?.current;
if (swaggerUI) {
const prevStateUrl = swaggerUIRef?.current?.specSelectors.url();
if (props.url !== prevStateUrl) {
// flush current content
swaggerUI.specActions.updateSpec('');
if (props.url) {
// update the internal URL
swaggerUI.specActions.updateUrl(props.url);
// trigger remote definition fetch
swaggerUI.system.specActions.download(props.url);
}
}
const prevStateSpec = swaggerUI.specSelectors.specStr();
if (props.spec && (props.spec !== prevStateSpec)) {
if (typeof props.spec === 'object') {
swaggerUI.specActions.updateSpec(JSON.stringify(props.spec));
} else {
swaggerUI.specActions.updateSpec(props.spec);
}
}
}
}, [props.spec, props.url]);
return <div ref={domNodeRef} />;
};

View File

@ -1,6 +1,6 @@
import { ButtonHTMLAttributes } from 'react'; import { ButtonHTMLAttributes } from 'react';
import styled, { css } from 'styled-components'; import styled, { css } from 'styled-components';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
export const ButtonSizeEnum = { export const ButtonSizeEnum = {
Default: 'default', Default: 'default',

View File

@ -1,6 +1,6 @@
import classnames from 'classnames'; import classnames from 'classnames';
import * as electron from 'electron'; import type { IpcRendererEvent } from 'electron';
import { IpcRendererEvent } from 'electron/renderer'; import { ipcRenderer } from 'electron';
import React, { FC, useEffect, useState } from 'react'; import React, { FC, useEffect, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
@ -125,9 +125,9 @@ export const Toast: FC = () => {
useEffect(() => { useEffect(() => {
const showNotification = (_: IpcRendererEvent, notification: ToastNotification) => handleNotification(notification); const showNotification = (_: IpcRendererEvent, notification: ToastNotification) => handleNotification(notification);
electron.ipcRenderer.on('show-notification', showNotification); ipcRenderer.on('show-notification', showNotification);
return () => { return () => {
electron.ipcRenderer.removeListener('show-notification', showNotification); ipcRenderer.removeListener('show-notification', showNotification);
}; };
}, []); }, []);

View File

@ -1,4 +1,4 @@
import { ipcRenderer } from 'electron/renderer'; import { ipcRenderer } from 'electron';
import { FC, useEffect } from 'react'; import { FC, useEffect } from 'react';
import { useAppCommands } from '../hooks/use-app-commands'; import { useAppCommands } from '../hooks/use-app-commands';

View File

@ -1,5 +1,5 @@
import { ServiceError, StatusObject } from '@grpc/grpc-js'; import { ServiceError, StatusObject } from '@grpc/grpc-js';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
import { generateId } from '../../../common/misc'; import { generateId } from '../../../common/misc';
import * as models from '../../../models'; import * as models from '../../../models';

View File

@ -3,7 +3,7 @@ import { renderHook } from '@testing-library/react';
import { mocked } from 'jest-mock'; import { mocked } from 'jest-mock';
import configureMockStore from 'redux-mock-store'; import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
import { PromiseValue } from 'type-fest'; import type { PromiseValue } from 'type-fest';
import { globalBeforeEach } from '../../../../__jest__/before-each'; import { globalBeforeEach } from '../../../../__jest__/before-each';
import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test'; import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test';

View File

@ -23,10 +23,10 @@
@import 'components/forms'; @import 'components/forms';
/* Variables */ /* Variables */
@import 'constants/animations'; @import './constants/animations';
@import 'constants/colors'; @import './constants/colors';
@import 'constants/dimensions'; @import './constants/dimensions';
@import 'constants/fonts'; @import './constants/fonts';
/* Components */ /* Components */
@import 'components/app'; @import 'components/app';

View File

@ -1,5 +1,5 @@
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import { RequireExactlyOne } from 'type-fest'; import type { RequireExactlyOne } from 'type-fest';
import { ACTIVITY_DEBUG, ACTIVITY_SPEC, GlobalActivity, isCollectionActivity, isDesignActivity } from '../../../common/constants'; import { ACTIVITY_DEBUG, ACTIVITY_SPEC, GlobalActivity, isCollectionActivity, isDesignActivity } from '../../../common/constants';
import * as models from '../../../models'; import * as models from '../../../models';

View File

@ -1,5 +1,5 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
import { isWorkspaceActivity, PREVIEW_MODE_SOURCE } from '../../common/constants'; import { isWorkspaceActivity, PREVIEW_MODE_SOURCE } from '../../common/constants';
import * as models from '../../models'; import * as models from '../../models';

View File

@ -1,10 +1,7 @@
import 'swagger-ui-react/swagger-ui.css';
import { IRuleResult } from '@stoplight/spectral-core'; import { IRuleResult } from '@stoplight/spectral-core';
import React, { createRef, FC, RefObject, useCallback, useEffect, useMemo, useState } from 'react'; import React, { createRef, FC, RefObject, useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import SwaggerUI from 'swagger-ui-react';
import { parseApiSpec, ParsedApiSpec } from '../../common/api-specs'; import { parseApiSpec, ParsedApiSpec } from '../../common/api-specs';
import { database } from '../../common/database'; import { database } from '../../common/database';
@ -17,6 +14,7 @@ import { ErrorBoundary } from '../components/error-boundary';
import { Notice, NoticeTable } from '../components/notice-table'; import { Notice, NoticeTable } from '../components/notice-table';
import { SidebarLayout } from '../components/sidebar-layout'; import { SidebarLayout } from '../components/sidebar-layout';
import { SpecEditorSidebar } from '../components/spec-editor/spec-editor-sidebar'; import { SpecEditorSidebar } from '../components/spec-editor/spec-editor-sidebar';
import { SwaggerUI } from '../components/swagger-ui';
import { superFaint } from '../css/css-in-js'; import { superFaint } from '../css/css-in-js';
import { useActiveApiSpecSyncVCSVersion, useGitVCSVersion } from '../hooks/use-vcs-version'; import { useActiveApiSpecSyncVCSVersion, useGitVCSVersion } from '../hooks/use-vcs-version';
import { selectActiveApiSpec } from '../redux/selectors'; import { selectActiveApiSpec } from '../redux/selectors';

View File

@ -1,11 +1,12 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"lib": ["DOM.Iterable"], "lib": ["DOM.Iterable", "DOM"],
"isolatedModules": true, "isolatedModules": true,
"jsx": "react", "jsx": "react",
"outDir": "./build", "outDir": "./build",
"rootDir": ".", "rootDir": ".",
"module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"strictNullChecks": true, "strictNullChecks": true,
"types": ["node", "vite/client"], "types": ["node", "vite/client"],

View File

@ -13,6 +13,7 @@
"send-request", "send-request",
"src", "src",
"vite.config.ts", "vite.config.ts",
"vite-plugin-electron-node-require"
], ],
"exclude": [ "exclude": [
"**/@types/mocha", "**/@types/mocha",

View File

@ -0,0 +1,102 @@
import { createRequire } from 'node:module';
import type {
Plugin,
} from 'vite';
export interface Options {
modules: string[];
}
/**
* Allows Vite to import modules that will be resolved by Node's require() function.
*/
export function electronNodeRequire(options: Options): Plugin {
const {
modules = [],
} = options;
return {
name: 'vite-plugin-electron-node-require',
config(conf) {
// Exclude the modules from Vite's dependency optimization (pre-bundling)
conf.optimizeDeps = {
...conf.optimizeDeps,
exclude: [
...conf.optimizeDeps?.exclude ? conf.optimizeDeps.exclude : [],
...modules,
],
};
// Create aliases for the modules so that we can resolve them with this plugin
conf.resolve ??= {};
conf.resolve.alias = {
...conf.resolve.alias,
...Object.fromEntries(modules.map(e => [e, `virtual:external:${e}`])),
};
// Ignore the modules from Rollup's commonjs plugin so that we can resolve them with this plugin
conf.build ??= {};
conf.build.commonjsOptions ??= {};
conf.build.commonjsOptions?.ignore ?? [];
conf.build.commonjsOptions.ignore = [
...modules,
];
return conf;
},
resolveId(id) {
const externalId = id.split('virtual:external:')[1];
if (modules.includes(externalId)) {
// Return a virtual module ID so that Vite knows to use this plugin to resolve the module
// The \0 is a special convention by Rollup to indicate that the module is virtual and should not be resolved by other plugins
return `\0${id}`;
}
// Return null to indicate that this plugin should not resolve the module
return null;
},
load(id) {
if (id.includes('virtual:external:')) {
const externalId = id.split('virtual:external:')[1];
// We need to handle electron because it's different when required in the renderer process
if (externalId === 'electron') {
return `
const electron = require('electron');
export { electron as default };
export const clipboard = electron.clipboard;
export const contextBridge = electron.contextBridge;
export const crashReporter = electron.crashReporter;
export const ipcRenderer = electron.ipcRenderer;
export const nativeImage = electron.nativeImage;
export const shell = electron.shell;
export const webFrame = electron.webFrame;
export const deprecate = electron.deprecate;
`;
}
const nodeRequire = createRequire(import.meta.url);
const exports = Object.keys(nodeRequire(externalId));
// Filter out the exports that are valid javascript variable keywords:
const validExports = exports.filter(e => {
try {
new Function(`const ${e} = true`);
return true;
} catch {
return false;
}
});
return [
`const requiredModule = require('${externalId}');`,
`${validExports.map(e => `export const ${e} = requiredModule.${e};`).join('\n')}`,
`${exports.includes('default') ? 'export default requiredModule.default;' : 'export default requiredModule'}`,
].join('\n');
}
// Return null to indicate that this plugin should not resolve the module
return null;
},
};
}

View File

@ -2,26 +2,9 @@ import react from '@vitejs/plugin-react';
import { builtinModules } from 'module'; import { builtinModules } from 'module';
import path from 'path'; import path from 'path';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import commonjsExternals from 'vite-plugin-commonjs-externals';
import pkg from './package.json'; import pkg from './package.json';
import { electronNodeRequire } from './vite-plugin-electron-node-require';
// The list of packages we want to keep as commonJS require().
// Must be resolvable import paths, cannot be globs
// These will be available via Node's require function from the node_modules folder or Node's builtin modules
const commonjsPackages = [
'electron',
'electron/main',
'electron/common',
'electron/renderer',
'@getinsomnia/node-libcurl',
'@getinsomnia/node-libcurl/dist/enum/CurlAuth',
'@getinsomnia/node-libcurl/dist/enum/CurlHttpVersion',
'@getinsomnia/node-libcurl/dist/enum/CurlNetrc',
'nunjucks/browser/nunjucks',
...Object.keys(pkg.dependencies),
...builtinModules,
];
export default defineConfig(({ mode }) => { export default defineConfig(({ mode }) => {
const __DEV__ = mode !== 'production'; const __DEV__ = mode !== 'production';
@ -35,14 +18,6 @@ export default defineConfig(({ mode }) => {
'process.env.NODE_ENV': JSON.stringify(mode), 'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.INSOMNIA_ENV': JSON.stringify(mode), 'process.env.INSOMNIA_ENV': JSON.stringify(mode),
}, },
resolve: {
alias: {
'url': path.join(__dirname, 'src', 'url.shim.js'),
},
},
optimizeDeps: {
exclude: commonjsPackages,
},
server: { server: {
port: pkg.dev['dev-server-port'], port: pkg.dev['dev-server-port'],
fs: { fs: {
@ -55,12 +30,25 @@ export default defineConfig(({ mode }) => {
assetsDir: './', assetsDir: './',
brotliSize: false, brotliSize: false,
emptyOutDir: false, emptyOutDir: false,
commonjsOptions: { rollupOptions: {
ignore: commonjsPackages, external: ['@getinsomnia/node-libcurl'],
}, },
}, },
optimizeDeps: {
exclude: ['@getinsomnia/node-libcurl'],
},
plugins: [ plugins: [
commonjsExternals({ externals: commonjsPackages }), // Allows us to import modules that will be resolved by Node's require() function.
// e.g. import fs from 'fs'; will get transformed to const fs = require('fs'); so that it works in the renderer process.
// This is necessary because we use nodeIntegration: true in the renderer process and allow importing modules from node.
electronNodeRequire({
modules: [
'electron',
...Object.keys(pkg.dependencies),
...builtinModules.filter(m => m !== 'buffer'),
...builtinModules.map(m => `node:${m}`),
],
}),
react({ react({
fastRefresh: __DEV__, fastRefresh: __DEV__,
jsxRuntime: 'automatic', jsxRuntime: 'automatic',

View File

@ -1,6 +1,6 @@
import SwaggerParser from '@apidevtools/swagger-parser'; import SwaggerParser from '@apidevtools/swagger-parser';
import { OpenAPIV3 } from 'openapi-types'; import { OpenAPIV3 } from 'openapi-types';
import { Entry } from 'type-fest'; import type { Entry } from 'type-fest';
import { distinctByProperty, getPluginNameFromKey, isPluginKey } from '../common'; import { distinctByProperty, getPluginNameFromKey, isPluginKey } from '../common';
import { DCPlugin } from '../types/declarative-config'; import { DCPlugin } from '../types/declarative-config';

View File

@ -1,4 +1,4 @@
import { ValueOf } from 'type-fest'; import type { ValueOf } from 'type-fest';
import { import {
distinctByProperty, distinctByProperty,

View File

@ -1,4 +1,4 @@
import { RequireAtLeastOne } from 'type-fest'; import type { RequireAtLeastOne } from 'type-fest';
import { DCRoute, DCService, DCUpstream } from './declarative-config'; import { DCRoute, DCService, DCUpstream } from './declarative-config';
import { Taggable } from './outputs'; import { Taggable } from './outputs';