-
-
Notifications
You must be signed in to change notification settings - Fork 520
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(template): add vite-typescript template (#3178)
Co-authored-by: Black-Hole <[email protected]>
- Loading branch information
1 parent
dee1970
commit f7018a9
Showing
16 changed files
with
445 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
tmpl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"name": "@electron-forge/template-vite-typescript", | ||
"version": "6.3.0", | ||
"description": "Vite-TypeScript template for Electron Forge, gets you started with Vite really quickly", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/electron/forge", | ||
"directory": "packages/template/vite-typescript" | ||
}, | ||
"author": "caoxiemeihao", | ||
"license": "MIT", | ||
"main": "dist/ViteTypeScriptTemplate.js", | ||
"typings": "dist/ViteTypeScriptTemplate.d.ts", | ||
"scripts": { | ||
"test": "mocha --config ../../../.mocharc.js test/**/*_spec_slow.ts" | ||
}, | ||
"engines": { | ||
"node": "^14.18.0 || >=16.0.0" | ||
}, | ||
"dependencies": { | ||
"@electron-forge/shared-types": "6.3.0", | ||
"@electron-forge/template-base": "6.3.0", | ||
"fs-extra": "^10.0.0" | ||
}, | ||
"devDependencies": { | ||
"@electron-forge/core-utils": "6.3.0", | ||
"@electron-forge/test-utils": "6.3.0", | ||
"chai": "^4.3.3", | ||
"fast-glob": "^3.2.7" | ||
}, | ||
"files": [ | ||
"dist", | ||
"src", | ||
"tmpl" | ||
] | ||
} |
72 changes: 72 additions & 0 deletions
72
packages/template/vite-typescript/src/ViteTypeScriptTemplate.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
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 ViteTypeScriptTemplate extends BaseTemplate { | ||
public templateDir = path.resolve(__dirname, '..', 'tmpl'); | ||
|
||
public async initializeTemplate(directory: string, options: InitTemplateOptions): Promise<ForgeListrTaskDefinition[]> { | ||
const superTasks = await super.initializeTemplate(directory, options); | ||
return [ | ||
...superTasks, | ||
{ | ||
title: 'Setting up Forge configuration', | ||
task: async () => { | ||
await this.copyTemplateFile(directory, 'forge.config.ts'); | ||
await fs.remove(path.resolve(directory, 'forge.config.js')); | ||
}, | ||
}, | ||
{ | ||
title: 'Preparing TypeScript files and configuration', | ||
task: async () => { | ||
const filePath = (fileName: string) => path.join(directory, 'src', fileName); | ||
|
||
// Copy Vite files | ||
await this.copyTemplateFile(directory, 'vite.main.config.ts'); | ||
await this.copyTemplateFile(directory, 'vite.renderer.config.ts'); | ||
await this.copyTemplateFile(directory, 'vite.preload.config.ts'); | ||
|
||
// Copy tsconfig with a small set of presets | ||
await this.copyTemplateFile(directory, 'tsconfig.json'); | ||
|
||
// Copy eslint config with recommended settings | ||
await this.copyTemplateFile(directory, '.eslintrc.json'); | ||
|
||
// Remove index.js and replace with main.ts | ||
await fs.remove(filePath('index.js')); | ||
await this.copyTemplateFile(path.join(directory, 'src'), 'main.ts'); | ||
|
||
await this.copyTemplateFile(path.join(directory, 'src'), 'renderer.ts'); | ||
await this.copyTemplateFile(path.join(directory, 'src'), 'types.d.ts'); | ||
|
||
// Remove preload.js and replace with preload.ts | ||
await fs.remove(filePath('preload.js')); | ||
await this.copyTemplateFile(path.join(directory, 'src'), 'preload.ts'); | ||
|
||
// TODO: Compatible with any path entry. | ||
// Vite uses index.html under the root path as the entry point. | ||
await fs.move(filePath('index.html'), path.join(directory, 'index.html')); | ||
await this.updateFileByLine(path.join(directory, 'index.html'), (line) => { | ||
if (line.includes('link rel="stylesheet"')) return ''; | ||
if (line.includes('</body>')) return ' <script type="module" src="/src/renderer.ts"></script>\n </body>'; | ||
return line; | ||
}); | ||
|
||
// update package.json | ||
const packageJSONPath = path.resolve(directory, 'package.json'); | ||
const packageJSON = await fs.readJson(packageJSONPath); | ||
packageJSON.main = '.vite/build/main.js'; | ||
// Configure scripts for TS template | ||
packageJSON.scripts.lint = 'eslint --ext .ts,.tsx .'; | ||
await fs.writeJson(packageJSONPath, packageJSON, { | ||
spaces: 2, | ||
}); | ||
}, | ||
}, | ||
]; | ||
} | ||
} | ||
|
||
export default new ViteTypeScriptTemplate(); |
144 changes: 144 additions & 0 deletions
144
packages/template/vite-typescript/test/ViteTypeScriptTemplate_spec_slow.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import cp from 'child_process'; | ||
import path from 'path'; | ||
|
||
import { yarnOrNpmSpawn } from '@electron-forge/core-utils'; | ||
import * as testUtils from '@electron-forge/test-utils'; | ||
import { expect } from 'chai'; | ||
import glob from 'fast-glob'; | ||
import fs from 'fs-extra'; | ||
|
||
import { api } from '../../../api/core'; | ||
import { initLink } from '../../../api/core/src/api/init-scripts/init-link'; | ||
|
||
describe('ViteTypeScriptTemplate', () => { | ||
let dir: string; | ||
|
||
before(async () => { | ||
await yarnOrNpmSpawn(['link:prepare']); | ||
dir = await testUtils.ensureTestDirIsNonexistent(); | ||
}); | ||
|
||
after(async () => { | ||
await yarnOrNpmSpawn(['link:remove']); | ||
await killWindowsEsbuildExe(); | ||
await fs.remove(dir); | ||
}); | ||
|
||
describe('template files are copied to project', () => { | ||
it('should succeed in initializing the typescript template', async () => { | ||
await api.init({ | ||
dir, | ||
template: path.resolve(__dirname, '..', 'src', 'ViteTypeScriptTemplate'), | ||
interactive: false, | ||
}); | ||
}); | ||
|
||
const expectedFiles = [ | ||
'tsconfig.json', | ||
'.eslintrc.json', | ||
'forge.config.ts', | ||
'vite.main.config.ts', | ||
'vite.renderer.config.ts', | ||
'vite.preload.config.ts', | ||
path.join('src', 'main.ts'), | ||
path.join('src', 'renderer.ts'), | ||
path.join('src', 'preload.ts'), | ||
path.join('src', 'types.d.ts'), | ||
]; | ||
for (const filename of expectedFiles) { | ||
it(`${filename} should exist`, async () => { | ||
await testUtils.expectProjectPathExists(dir, filename, 'file'); | ||
}); | ||
} | ||
|
||
it('should ensure js source files from base template are removed', async () => { | ||
const jsFiles = await glob(path.join(dir, 'src', '**', '*.js')); | ||
expect(jsFiles.length).to.equal(0, `The following unexpected js files were found in the src/ folder: ${JSON.stringify(jsFiles)}`); | ||
}); | ||
}); | ||
|
||
describe('lint', () => { | ||
it('should initially pass the linting process', async () => { | ||
delete process.env.TS_NODE_PROJECT; | ||
await testUtils.expectLintToPass(dir); | ||
}); | ||
}); | ||
|
||
describe('package', () => { | ||
let cwd: string; | ||
|
||
before(async () => { | ||
delete process.env.TS_NODE_PROJECT; | ||
// Vite resolves plugins via cwd | ||
cwd = process.cwd(); | ||
process.chdir(dir); | ||
// We need the version of vite to match exactly during development due to a quirk in | ||
// typescript type-resolution. In prod no one has to worry about things like this | ||
const pj = await fs.readJson(path.resolve(dir, 'package.json')); | ||
pj.resolutions = { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
vite: `${require('../../../../node_modules/vite/package.json').version}`, | ||
}; | ||
await fs.writeJson(path.resolve(dir, 'package.json'), pj); | ||
await yarnOrNpmSpawn(['install'], { | ||
cwd: dir, | ||
}); | ||
|
||
// Installing deps removes symlinks that were added at the start of this | ||
// spec via `api.init`. So we should re-link local forge dependencies | ||
// again. | ||
await initLink(dir); | ||
}); | ||
|
||
after(() => { | ||
process.chdir(cwd); | ||
}); | ||
|
||
it('should pass', async () => { | ||
await api.package({ | ||
dir, | ||
interactive: false, | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
/** | ||
* TODO: resolve `esbuild` can not exit normally on the Windows platform. | ||
* @deprecated | ||
*/ | ||
async function killWindowsEsbuildExe() { | ||
if (process.platform !== 'win32') { | ||
return Promise.resolve(); | ||
} | ||
|
||
return new Promise<void>((resolve, reject) => { | ||
cp.exec('tasklist', (error, stdout) => { | ||
if (error) { | ||
reject(error); | ||
return; | ||
} | ||
|
||
const esbuild = stdout | ||
.toString() | ||
.split('\n') | ||
.map((line) => line.split(/\s+/)) | ||
.find((line) => line.includes('esbuild.exe')); | ||
|
||
if (!esbuild) { | ||
resolve(); | ||
return; | ||
} | ||
|
||
// ['esbuild.exe', '4564', 'Console', '1', '14,400', 'K', ''] | ||
const [, pid] = esbuild; | ||
const result = process.kill(+pid, 'SIGINT'); | ||
|
||
if (result) { | ||
resolve(); | ||
} else { | ||
reject(new Error('kill esbuild process failed')); | ||
} | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"env": { | ||
"browser": true, | ||
"es6": true, | ||
"node": true | ||
}, | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:import/recommended", | ||
"plugin:import/electron", | ||
"plugin:import/typescript" | ||
], | ||
"parser": "@typescript-eslint/parser" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import type { ForgeConfig } from '@electron-forge/shared-types'; | ||
import { MakerSquirrel } from '@electron-forge/maker-squirrel'; | ||
import { MakerZIP } from '@electron-forge/maker-zip'; | ||
import { MakerDeb } from '@electron-forge/maker-deb'; | ||
import { MakerRpm } from '@electron-forge/maker-rpm'; | ||
import { VitePlugin } from '@electron-forge/plugin-vite'; | ||
|
||
const config: ForgeConfig = { | ||
packagerConfig: {}, | ||
rebuildConfig: {}, | ||
makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})], | ||
plugins: [ | ||
new VitePlugin({ | ||
// `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc. | ||
// If you are familiar with Vite configuration, it will look really familiar. | ||
build: [ | ||
{ | ||
// `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`. | ||
entry: 'src/main.ts', | ||
config: 'vite.main.config.ts', | ||
}, | ||
{ | ||
entry: 'src/preload.ts', | ||
config: 'vite.preload.config.ts', | ||
}, | ||
], | ||
renderer: [ | ||
{ | ||
name: 'main_window', | ||
config: 'vite.renderer.config.ts', | ||
}, | ||
], | ||
}), | ||
], | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { app, BrowserWindow } from 'electron'; | ||
import path from 'path'; | ||
|
||
// Handle creating/removing shortcuts on Windows when installing/uninstalling. | ||
if (require('electron-squirrel-startup')) { | ||
app.quit(); | ||
} | ||
|
||
const createWindow = () => { | ||
// Create the browser window. | ||
const mainWindow = new BrowserWindow({ | ||
width: 800, | ||
height: 600, | ||
webPreferences: { | ||
preload: path.join(__dirname, 'preload.js'), | ||
}, | ||
}); | ||
|
||
// and load the index.html of the app. | ||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { | ||
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); | ||
} else { | ||
mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)); | ||
} | ||
|
||
// Open the DevTools. | ||
mainWindow.webContents.openDevTools(); | ||
}; | ||
|
||
// This method will be called when Electron has finished | ||
// initialization and is ready to create browser windows. | ||
// Some APIs can only be used after this event occurs. | ||
app.on('ready', createWindow); | ||
|
||
// Quit when all windows are closed, except on macOS. There, it's common | ||
// for applications and their menu bar to stay active until the user quits | ||
// explicitly with Cmd + Q. | ||
app.on('window-all-closed', () => { | ||
if (process.platform !== 'darwin') { | ||
app.quit(); | ||
} | ||
}); | ||
|
||
app.on('activate', () => { | ||
// On OS X it's common to re-create a window in the app when the | ||
// dock icon is clicked and there are no other windows open. | ||
if (BrowserWindow.getAllWindows().length === 0) { | ||
createWindow(); | ||
} | ||
}); | ||
|
||
// In this file you can include the rest of your app's specific main process | ||
// code. You can also put them in separate files and import them here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"devDependencies": { | ||
"@electron-forge/plugin-vite": "ELECTRON_FORGE/VERSION", | ||
"@typescript-eslint/eslint-plugin": "^5.0.0", | ||
"@typescript-eslint/parser": "^5.0.0", | ||
"eslint": "^8.0.1", | ||
"eslint-plugin-import": "^2.25.0", | ||
"ts-node": "^10.0.0", | ||
"typescript": "~4.5.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.