diff --git a/package.json b/package.json index 987d8c145c..2ecab10438 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "source-map-support": "^0.5.13", "sudo-prompt": "^9.1.1", "username": "^5.1.0", + "vite": "^3.2.3", "webpack": "^5.69.1", "webpack-dev-server": "^4.0.0", "webpack-merge": "^5.7.3", diff --git a/packages/plugin/vite/README.md b/packages/plugin/vite/README.md new file mode 100644 index 0000000000..809a89854d --- /dev/null +++ b/packages/plugin/vite/README.md @@ -0,0 +1,30 @@ +## plugin-vite + +This plugin makes it easy to set up standard vite tooling to compile both your main process code and your renderer process code, with built-in support for Hot Module Replacement (HMR) in the renderer process and support for multiple renderers. + +``` +// forge.config.js + +module.exports = { + plugins: [ + { + name: '@electron-forge/plugin-vite', + config: { + mainConfig: './vite.main.config.js', + renderer: { + config: './vite.renderer.config.js', + entryPoints: [ + { + html: './src/index.html', + name: 'main_window', + preload: { + js: './src/preload.js', + }, + }, + ], + }, + }, + } + ] +} +``` \ No newline at end of file diff --git a/packages/plugin/vite/package.json b/packages/plugin/vite/package.json new file mode 100644 index 0000000000..7c4f912808 --- /dev/null +++ b/packages/plugin/vite/package.json @@ -0,0 +1,31 @@ +{ + "name": "@electron-forge/plugin-vite", + "version": "0.0.0", + "description": "Vite plugin for Electron Forge, lets you use Vite directly in your tooling", + "repository": { + "type": "git", + "url": "https://github.com/electron/forge", + "directory": "packages/plugin/vite" + }, + "author": "caoxiemeihao", + "license": "MIT", + "main": "dist/VitePlugin.js", + "typings": "dist/VitePlugin.d.ts", + "scripts": {}, + "devDependencies": { + "@types/node": "^18.0.3" + }, + "engines": { + "node": ">= 14.18.0" + }, + "dependencies": { + "@electron-forge/core-utils": "6.0.1", + "@electron-forge/plugin-base": "6.0.1", + "@electron-forge/shared-types": "6.0.1", + "@electron-forge/web-multi-logger": "6.0.1", + "chalk": "^4.0.0", + "debug": "^4.3.1", + "fs-extra": "^10.0.0", + "vite": "^3.2.3" + } +} diff --git a/packages/plugin/vite/src/Config.ts b/packages/plugin/vite/src/Config.ts new file mode 100644 index 0000000000..088f5c0adc --- /dev/null +++ b/packages/plugin/vite/src/Config.ts @@ -0,0 +1,50 @@ +export interface VitePreloadEntryPoint { + /** + * Relative or absolute path to the preload JS file. + */ + js: string; + /** + * The optional vite config for your preload process. + * Defaults to the renderer vite config if blank. + */ + config?: string; +} + +export interface VitePluginEntryPointBase { + /** + * Human friendly name of your entry point + */ + name: string; +} + +export interface VitePluginEntryPoint extends VitePluginEntryPointBase { + /** + * Relative or absolute path to the HTML template file for this entry point. + */ + html: string; + /** + * Information about the preload script for this entry point. If you don't use + * preload scripts, you don't need to set this. + */ + preload?: VitePreloadEntryPoint; +} + +export interface VitePluginRendererConfig { + /** + * The vite config for your renderer process + */ + config: string; + /** + * Array of entry points, these should map to the windows your app needs to + * open. Each window requires it's own entry point + */ + entryPoints: VitePluginEntryPoint[]; +} + +export interface VitePluginConfig { + /** + * The vite config for your main process + */ + mainConfig: string; + renderer: VitePluginRendererConfig; +} diff --git a/packages/plugin/vite/src/ViteConfig.ts b/packages/plugin/vite/src/ViteConfig.ts new file mode 100644 index 0000000000..48209abd78 --- /dev/null +++ b/packages/plugin/vite/src/ViteConfig.ts @@ -0,0 +1,83 @@ +import path from 'node:path'; + +import debug from 'debug'; + +import { VitePluginConfig, VitePluginEntryPoint } from './Config'; + +type ViteMode = 'production' | 'development'; + +const d = debug('electron-forge:plugin:webpack:webpackconfig'); + +export default class ViteConfigGenerator { + private isProd: boolean; + + private pluginConfig: VitePluginConfig; + + private port: number; + + private projectDir!: string; + + private baseDir!: string; + + constructor(pluginConfig: VitePluginConfig, projectDir: string, isProd: boolean, port: number) { + this.pluginConfig = pluginConfig; + this.projectDir = projectDir; + this.baseDir = path.resolve(projectDir, '.vite'); + this.isProd = isProd; + this.port = port; + + d('Config mode:', this.mode); + } + + get mode(): ViteMode { + return this.isProd ? 'production' : 'development'; + } + + private rendererEntryPoint(entryPoint: VitePluginEntryPoint, inRendererDir: boolean, basename: string): string { + if (this.isProd) { + return `\`file://$\{require('path').resolve(__dirname, '..', '${inRendererDir ? 'renderer' : '.'}', '${entryPoint.name}', '${basename}')}\``; + } + const baseUrl = `http://localhost:${this.port}/${entryPoint.name}`; + if (basename !== 'index.html') { + return `'${baseUrl}/${basename}'`; + } + return `'${baseUrl}'`; + } + + getDefines(inRendererDir = true): Record { + const defines: Record = {}; + if (!this.pluginConfig.renderer.entryPoints || !Array.isArray(this.pluginConfig.renderer.entryPoints)) { + throw new Error('Required config option "renderer.entryPoints" has not been defined'); + } + for (const entryPoint of this.pluginConfig.renderer.entryPoints) { + const entryKey = this.toEnvironmentVariable(entryPoint); + // Vite uses html files as the entry point, so the html file is always present. + defines[entryKey] = this.rendererEntryPoint(entryPoint, inRendererDir, 'index.html'); + defines[`process.env.${entryKey}`] = defines[entryKey]; + + const preloadDefineKey = this.toEnvironmentVariable(entryPoint, true); + defines[preloadDefineKey] = this.getPreloadDefine(entryPoint); + defines[`process.env.${preloadDefineKey}`] = defines[preloadDefineKey]; + } + + return defines; + } + + private toEnvironmentVariable(entryPoint: VitePluginEntryPoint, preload = false): string { + const suffix = preload ? '_PRELOAD_WEBPACK_ENTRY' : '_WEBPACK_ENTRY'; + return `${entryPoint.name.toUpperCase().replace(/ /g, '_')}${suffix}`; + } + + private getPreloadDefine(entryPoint: VitePluginEntryPoint): string { + if (entryPoint.preload?.js) { + if (this.isProd) { + return `require('path').resolve(__dirname, '../renderer', '${entryPoint.name}', 'preload.js')`; + } + return `'${path.resolve(this.baseDir, 'renderer', entryPoint.name, 'preload.js').replace(/\\/g, '\\\\')}'`; + } else { + // If this entry-point has no configured preload script just map this constant to `undefined` + // so that any code using it still works. This makes quick-start / docs simpler. + return 'undefined'; + } + } +} diff --git a/packages/plugin/vite/src/VitePlugin.ts b/packages/plugin/vite/src/VitePlugin.ts new file mode 100644 index 0000000000..ee7e2a23ab --- /dev/null +++ b/packages/plugin/vite/src/VitePlugin.ts @@ -0,0 +1,215 @@ +import fs from 'node:fs'; +import http from 'node:http'; +import path from 'node:path'; + +import { namedHookWithTaskFn, PluginBase } from '@electron-forge/plugin-base'; +import { ForgeMultiHookMap, StartResult } from '@electron-forge/shared-types'; +import debug from 'debug'; +// eslint-disable-next-line node/no-extraneous-import +import { RollupWatcher } from 'rollup'; +import { default as vite } from 'vite'; + +import { VitePluginConfig } from './Config'; +import ViteConfigGenerator from './ViteConfig'; + +const d = debug('electron-forge:plugin:vite'); +const DEFAULT_PORT = 3000; + +export default class VitePlugin extends PluginBase { + name = 'vite'; + + private isProd = false; + + // The root of the Electron app + private projectDir!: string; + + // Where the Vite output is generated. Usually `${projectDir}/.vite` + private baseDir!: string; + + private configGenerator: Promise; + + private watchers: RollupWatcher[] = []; + + private servers: http.Server[] = []; + + constructor(c: VitePluginConfig) { + super(c); + + this.configGenerator = new Promise((resolve) => { + // eslint-disable-next-line promise/catch-or-return + vite.resolveConfig({ configFile: this.config.renderer.config }, 'serve').then((resolvedConfig) => { + // Get the user to set port in vite config file. + resolve(new ViteConfigGenerator(this.config, this.projectDir, this.isProd, resolvedConfig.server.port ?? DEFAULT_PORT)); + return; + }); + }); + } + + init = (dir: string): void => { + this.setDirectories(dir); + + d('hooking process events'); + process.on('exit', (_code) => this.exitHandler({ cleanup: true })); + process.on('SIGINT' as NodeJS.Signals, (_signal) => this.exitHandler({ exit: true })); + }; + + setDirectories = (dir: string): void => { + this.projectDir = dir; + this.baseDir = path.resolve(dir, '.vite'); + }; + + getHooks = (): ForgeMultiHookMap => { + return { + prePackage: [ + namedHookWithTaskFn<'prePackage'>(async () => { + this.isProd = true; + fs.rmSync(this.baseDir, { recursive: true, force: true }); + + await this.compileMain(); + await this.compileRenderers(); + }, 'Building vite bundles'), + ], + }; + }; + + private alreadyStarted = false; + startLogic = async (): Promise => { + if (this.alreadyStarted) return false; + this.alreadyStarted = true; + + fs.rmSync(this.baseDir, { recursive: true, force: true }); + + return { + tasks: [ + { + title: 'Compiling main process code', + task: async () => { + await this.compileMain(true); + }, + options: { + showTimer: true, + }, + }, + { + title: 'Launching dev servers for renderer process code', + task: async () => { + await this.launchRendererDevServers(); + }, + options: { + persistentOutput: true, + showTimer: true, + }, + }, + ], + result: false, + }; + }; + + compileMain = async (watch = false): Promise => { + const buildResult = await vite.build({ + configFile: this.config.mainConfig, + + // However, bllow config options aways merge into `configFile`. + build: { + watch: watch ? {} : null, + outDir: path.join(this.baseDir, 'main'), + }, + define: (await this.configGenerator).getDefines(), + }); + + if (watch) { + this.watchers.push(buildResult as RollupWatcher); + } + }; + + compileRenderers = async (): Promise => { + const { config: configFile, entryPoints } = this.config.renderer; + + for (const entry of entryPoints) { + await vite.build({ + configFile, + + // However, bllow config options aways merge into `configFile`. + build: { + outDir: path.join(this.baseDir, 'renderer', entry.name), + rollupOptions: { + input: entry.html, + }, + }, + }); + } + + await this.compilePreload(); + }; + + compilePreload = async (watch = false): Promise => { + await Promise.all( + this.config.renderer.entryPoints.map(async (entry) => { + if (entry.preload) { + const buildResult = await vite.build({ + configFile: this.config.mainConfig, + + // However, bllow config options aways merge into `configFile`. + build: { + lib: { + entry: entry.preload.js, + // At present, Electron can only support CommonJs. + formats: ['cjs'], + fileName: () => '[name].js', + }, + watch: watch ? {} : null, + outDir: path.join(this.baseDir, 'renderer', entry.name), + }, + }); + + if (watch) { + this.watchers.push(buildResult as RollupWatcher); + } + } + }) + ); + }; + + launchRendererDevServers = async (): Promise => { + const { config: configFile, entryPoints } = this.config.renderer; + const viteDevServer = await vite.createServer({ + configFile, + + // However, bllow config options aways merge into `configFile`. + build: { + rollupOptions: { + input: entryPoints.map((entry) => entry.html), + }, + }, + }); + + await viteDevServer.listen(); + viteDevServer.printUrls(); + + if (viteDevServer.httpServer) { + this.servers.push(viteDevServer.httpServer); + } + + await this.compilePreload(true); + }; + + exitHandler = (options: { cleanup?: boolean; exit?: boolean }, err?: Error): void => { + d('handling process exit with:', options); + if (options.cleanup) { + for (const watcher of this.watchers) { + d('cleaning vite watcher'); + watcher.close(); + } + this.watchers = []; + for (const server of this.servers) { + d('cleaning http server'); + server.close(); + } + this.servers = []; + } + if (err) console.error(err.stack); + // Why: This is literally what the option says to do. + // eslint-disable-next-line no-process-exit + if (options.exit) process.exit(); + }; +} diff --git a/packages/template/vite/.eslintignore b/packages/template/vite/.eslintignore new file mode 100644 index 0000000000..364f7cc60e --- /dev/null +++ b/packages/template/vite/.eslintignore @@ -0,0 +1 @@ +tmpl \ No newline at end of file diff --git a/packages/template/vite/package.json b/packages/template/vite/package.json new file mode 100644 index 0000000000..0386c2599c --- /dev/null +++ b/packages/template/vite/package.json @@ -0,0 +1,26 @@ +{ + "name": "@electron-forge/template-vite", + "version": "6.0.1", + "description": "Vite template for Electron Forge, gets you started with Vite really quickly", + "repository": "https://github.com/electron/forge", + "author": "Samuel Attard", + "license": "MIT", + "main": "dist/ViteTemplate.js", + "typings": "dist/ViteTemplate.d.ts", + "scripts": { + "test": "mocha --config ../../../.mocharc.js test/**/*_spec.ts" + }, + "engines": { + "node": ">= 14.17.5" + }, + "dependencies": { + "@electron-forge/shared-types": "6.0.1", + "@electron-forge/template-base": "6.0.1", + "fs-extra": "^10.0.0" + }, + "devDependencies": { + "@electron-forge/test-utils": "6.0.1", + "chai": "^4.3.3", + "listr2": "^5.0.3" + } +} diff --git a/packages/template/vite/src/ViteTemplate.ts b/packages/template/vite/src/ViteTemplate.ts new file mode 100644 index 0000000000..f2bc33afd2 --- /dev/null +++ b/packages/template/vite/src/ViteTemplate.ts @@ -0,0 +1,57 @@ +import path from 'path'; + +import { ForgeListrTaskDefinition, InitTemplateOptions } from '@electron-forge/shared-types'; +import { BaseTemplate } from '@electron-forge/template-base'; +import fs from 'fs-extra'; + +class ViteTemplate extends BaseTemplate { + public templateDir = path.resolve(__dirname, '..', 'tmpl'); + + public async initializeTemplate(directory: string, options: InitTemplateOptions): Promise { + const superTasks = await super.initializeTemplate(directory, options); + return [ + ...superTasks, + { + title: 'Setting up Forge configuration', + task: async () => { + await this.copyTemplateFile(directory, 'forge.config.js'); + }, + }, + { + title: 'Setting up vite configuration', + task: async () => { + await this.copyTemplateFile(directory, 'vite.main.config.js'); + await this.copyTemplateFile(directory, 'vite.renderer.config.js'); + await this.copyTemplateFile(path.join(directory, 'src'), 'renderer.js'); + await this.copyTemplateFile(path.join(directory, 'src'), 'preload.js'); + + await this.updateFileByLine( + path.resolve(directory, 'src', 'index.js'), + (line) => { + if (line.includes('mainWindow.loadFile')) return ' mainWindow.loadURL(MAIN_WINDOW_VITE_ENTRY);'; + if (line.includes('preload: ')) return ' preload: MAIN_WINDOW_PRELOAD_VITE_ENTRY,'; + return line; + }, + path.resolve(directory, 'src', 'main.js') + ); + + await this.updateFileByLine(path.resolve(directory, 'src', 'index.html'), (line) => { + if (line.includes('link rel="stylesheet"')) return ''; + if (line.includes('')) return ' \n '; + return line; + }); + + // update package.json entry point + const pjPath = path.resolve(directory, 'package.json'); + const currentPJ = await fs.readJson(pjPath); + currentPJ.main = '.vite/main'; + await fs.writeJson(pjPath, currentPJ, { + spaces: 2, + }); + }, + }, + ]; + } +} + +export default new ViteTemplate(); diff --git a/packages/template/vite/test/ViteTemplate_spec.ts b/packages/template/vite/test/ViteTemplate_spec.ts new file mode 100644 index 0000000000..09caaff8fd --- /dev/null +++ b/packages/template/vite/test/ViteTemplate_spec.ts @@ -0,0 +1,52 @@ +import path from 'path'; + +import * as testUtils from '@electron-forge/test-utils'; +import { expect } from 'chai'; +import fs from 'fs-extra'; +import { Listr } from 'listr2'; + +import template from '../src/ViteTemplate'; + +describe('ViteTemplate', () => { + let dir: string; + + before(async () => { + dir = await testUtils.ensureTestDirIsNonexistent(); + }); + + it('should succeed in initializing the vite template', async () => { + const tasks = await template.initializeTemplate(dir, {}); + const runner = new Listr(tasks, { concurrent: false, exitOnError: false }); + await runner.run(); + expect(runner.err).to.have.lengthOf(0); + }); + + context('template files are copied to project', () => { + const expectedFiles = ['vite.main.config.js', 'vite.renderer.config.js', path.join('src', 'renderer.js'), path.join('src', 'preload.js')]; + for (const filename of expectedFiles) { + it(`${filename} should exist`, async () => { + await testUtils.expectProjectPathExists(dir, filename, 'file'); + }); + } + }); + + it('should move and rewrite the main process file', async () => { + await testUtils.expectProjectPathNotExists(dir, path.join('src', 'index.js'), 'file'); + await testUtils.expectProjectPathExists(dir, path.join('src', 'main.js'), 'file'); + const mainFile = (await fs.readFile(path.join(dir, 'src', 'main.js'))).toString(); + expect(mainFile).to.match(/MAIN_WINDOW_VITE_ENTRY/); + expect(mainFile).to.match(/MAIN_WINDOW_PRELOAD_VITE_ENTRY/); + }); + + it('should remove the stylesheet link from the HTML file', async () => { + expect((await fs.readFile(path.join(dir, 'src', 'index.html'))).toString()).to.not.match(/link rel="stylesheet"/); + }); + + it('should inject script into the HTML file', async () => { + expect((await fs.readFile(path.join(dir, 'src', 'index.html'))).toString()).to.match(/src="\/renderer\.js"/); + }); + + after(async () => { + await fs.remove(dir); + }); +}); diff --git a/packages/template/vite/tmpl/forge.config.js b/packages/template/vite/tmpl/forge.config.js new file mode 100644 index 0000000000..29a11fdccb --- /dev/null +++ b/packages/template/vite/tmpl/forge.config.js @@ -0,0 +1,42 @@ +module.exports = { + packagerConfig: {}, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: {}, + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: {}, + }, + { + name: '@electron-forge/maker-rpm', + config: {}, + }, + ], + plugins: [ + { + name: '@electron-forge/plugin-vite', + config: { + mainConfig: './vite.main.config.js', + renderer: { + config: './vite.renderer.config.js', + entryPoints: [ + { + html: './src/index.html', + name: 'main_window', + preload: { + js: './src/preload.js', + }, + }, + ], + }, + }, + }, + ], +}; diff --git a/packages/template/vite/tmpl/package.json b/packages/template/vite/tmpl/package.json new file mode 100644 index 0000000000..03feaefeef --- /dev/null +++ b/packages/template/vite/tmpl/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "@electron-forge/plugin-vite": "ELECTRON_FORGE/VERSION" + } +} diff --git a/packages/template/vite/tmpl/preload.js b/packages/template/vite/tmpl/preload.js new file mode 100644 index 0000000000..5e9d369cc9 --- /dev/null +++ b/packages/template/vite/tmpl/preload.js @@ -0,0 +1,2 @@ +// See the Electron documentation for details on how to use preload scripts: +// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts diff --git a/packages/template/vite/tmpl/renderer.js b/packages/template/vite/tmpl/renderer.js new file mode 100644 index 0000000000..4efeddb622 --- /dev/null +++ b/packages/template/vite/tmpl/renderer.js @@ -0,0 +1,31 @@ +/** + * This file will automatically be loaded by vite and run in the "renderer" context. + * To learn more about the differences between the "main" and the "renderer" context in + * Electron, visit: + * + * https://electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes + * + * By default, Node.js integration in this file is disabled. When enabling Node.js integration + * in a renderer process, please be aware of potential security implications. You can read + * more about security risks here: + * + * https://electronjs.org/docs/tutorial/security + * + * To enable Node.js integration in this file, open up `main.js` and enable the `nodeIntegration` + * flag: + * + * ``` + * // Create the browser window. + * mainWindow = new BrowserWindow({ + * width: 800, + * height: 600, + * webPreferences: { + * nodeIntegration: true + * } + * }); + * ``` + */ + +import './index.css'; + +console.log('👋 This message is being logged by "renderer.js", included via vite'); diff --git a/packages/template/vite/tmpl/vite.main.config.js b/packages/template/vite/tmpl/vite.main.config.js new file mode 100644 index 0000000000..9f5eeea2c1 --- /dev/null +++ b/packages/template/vite/tmpl/vite.main.config.js @@ -0,0 +1,11 @@ +module.exports = { + build: { + lib: { + /** + * This is the main entry point for your application, it's the first file + * that runs in the main process. + */ + entry: './src/main.js', + }, + }, +}; diff --git a/packages/template/vite/tmpl/vite.preload.config.js b/packages/template/vite/tmpl/vite.preload.config.js new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/packages/template/vite/tmpl/vite.preload.config.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/packages/template/vite/tmpl/vite.renderer.config.js b/packages/template/vite/tmpl/vite.renderer.config.js new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/packages/template/vite/tmpl/vite.renderer.config.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/yarn.lock b/yarn.lock index d0021ca8bf..587c524e36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1194,6 +1194,16 @@ minimatch "^3.0.4" plist "^3.0.4" +"@esbuild/android-arm@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.13.tgz#ce11237a13ee76d5eae3908e47ba4ddd380af86a" + integrity sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw== + +"@esbuild/linux-loong64@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz#64e8825bf0ce769dac94ee39d92ebe6272020dfc" + integrity sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -4171,6 +4181,134 @@ es6-weak-map@^2.0.1: es6-iterator "^2.0.3" es6-symbol "^3.1.1" +esbuild-android-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz#5f25864055dbd62e250f360b38b4c382224063af" + integrity sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g== + +esbuild-android-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz#d8820f999314efbe8e0f050653a99ff2da632b0f" + integrity sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w== + +esbuild-darwin-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz#99ae7fdaa43947b06cd9d1a1c3c2c9f245d81fd0" + integrity sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg== + +esbuild-darwin-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz#bafa1814354ad1a47adcad73de416130ef7f55e3" + integrity sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A== + +esbuild-freebsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz#84ef85535c5cc38b627d1c5115623b088d1de161" + integrity sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA== + +esbuild-freebsd-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz#033f21de434ec8e0c478054b119af8056763c2d8" + integrity sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q== + +esbuild-linux-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz#54290ea8035cba0faf1791ce9ae6693005512535" + integrity sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w== + +esbuild-linux-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz#4264249281ea388ead948614b57fb1ddf7779a2c" + integrity sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A== + +esbuild-linux-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz#9323c333924f97a02bdd2ae8912b36298acb312d" + integrity sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ== + +esbuild-linux-arm@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz#b407f47b3ae721fe4e00e19e9f19289bef87a111" + integrity sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ== + +esbuild-linux-mips64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz#bdf905aae5c0bcaa8f83567fe4c4c1bdc1f14447" + integrity sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A== + +esbuild-linux-ppc64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz#2911eae1c90ff58a3bd3259cb557235df25aa3b4" + integrity sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA== + +esbuild-linux-riscv64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz#1837c660be12b1d20d2a29c7189ea703f93e9265" + integrity sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow== + +esbuild-linux-s390x@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz#d52880ece229d1bd10b2d936b792914ffb07c7fc" + integrity sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag== + +esbuild-netbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz#de14da46f1d20352b43e15d97a80a8788275e6ed" + integrity sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ== + +esbuild-openbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz#45e8a5fd74d92ad8f732c43582369c7990f5a0ac" + integrity sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w== + +esbuild-sunos-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz#f646ac3da7aac521ee0fdbc192750c87da697806" + integrity sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw== + +esbuild-windows-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz#fb4fe77c7591418880b3c9b5900adc4c094f2401" + integrity sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA== + +esbuild-windows-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz#1fca8c654392c0c31bdaaed168becfea80e20660" + integrity sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ== + +esbuild-windows-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz#4ffd01b6b2888603f1584a2fe96b1f6a6f2b3dd8" + integrity sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg== + +esbuild@^0.15.9: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.13.tgz#7293480038feb2bafa91d3f6a20edab3ba6c108a" + integrity sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ== + optionalDependencies: + "@esbuild/android-arm" "0.15.13" + "@esbuild/linux-loong64" "0.15.13" + esbuild-android-64 "0.15.13" + esbuild-android-arm64 "0.15.13" + esbuild-darwin-64 "0.15.13" + esbuild-darwin-arm64 "0.15.13" + esbuild-freebsd-64 "0.15.13" + esbuild-freebsd-arm64 "0.15.13" + esbuild-linux-32 "0.15.13" + esbuild-linux-64 "0.15.13" + esbuild-linux-arm "0.15.13" + esbuild-linux-arm64 "0.15.13" + esbuild-linux-mips64le "0.15.13" + esbuild-linux-ppc64le "0.15.13" + esbuild-linux-riscv64 "0.15.13" + esbuild-linux-s390x "0.15.13" + esbuild-netbsd-64 "0.15.13" + esbuild-openbsd-64 "0.15.13" + esbuild-sunos-64 "0.15.13" + esbuild-windows-32 "0.15.13" + esbuild-windows-64 "0.15.13" + esbuild-windows-arm64 "0.15.13" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -6917,6 +7055,11 @@ nanoid@3.3.1: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -7631,6 +7774,15 @@ plist@^3.0.4, plist@^3.0.5: base64-js "^1.5.1" xmlbuilder "^15.1.1" +postcss@^8.4.18: + version "8.4.19" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" + integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -8007,7 +8159,7 @@ resolve@^1.1.6, resolve@^1.10.1, resolve@^1.11.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.0: +resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -8100,6 +8252,13 @@ roarr@^2.15.3: semver-compare "^1.0.0" sprintf-js "^1.1.2" +rollup@^2.79.1: + version "2.79.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" + integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== + optionalDependencies: + fsevents "~2.3.2" + run-async@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -8450,6 +8609,11 @@ socks@^2.6.2: ip "^2.0.0" smart-buffer "^4.2.0" +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-support@^0.5.13, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -9185,6 +9349,18 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vite@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.3.tgz#7a68d9ef73eff7ee6dc0718ad3507adfc86944a7" + integrity sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ== + dependencies: + esbuild "^0.15.9" + postcss "^8.4.18" + resolve "^1.22.1" + rollup "^2.79.1" + optionalDependencies: + fsevents "~2.3.2" + vscode-oniguruma@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz#2bf4dfcfe3dd2e56eb549a3068c8ee39e6c30ce5"