Foreword
Recently I was working on an electron ecology-related project. Since I had to do some project initialization functions, I wrote a scaffolding to do this. Then I learned about and practiced the scaffolding-related functions in detail, and finally succeeded in making it. I think If you need the scaffolding, share your relevant experiences here.
Let’s take a look at Vite’s official website first.
The goal we want to achieve is the same. yarn create electron-prokit myapp
can quickly build an electron project directly.
What is npm create
Just run it from the command line and you’ll know
npm create --help
In other words, npm create is actually an alias of npm init
This method can be used to build the app when node version >=6.10
npm
will splice create-
in front of the initial item you provide and then use the npx
tool to download and execute the method, that is
npm create vite // Equivalent to npm init vite // Equivalent to npx create-vite // Equivalent to npm install create-vite -g & amp; & amp; create-vite
So npm create vite
means using the create-vite
scaffolding to create a vite project.
The same goes for yarn
: https://classic.yarnpkg.com/en/docs/cli/create
Once you understand this, you can start designing the scaffolding.
Scaffolding function
Our scaffolding is named create-electron-prokit
. As the name suggests, it is a generator for the electron-prokit
series of projects. Its main function is to produce electron-prokit
Related projects, split details, our function points are as follows.
- Receives the project name, description, etc. input by the user, and is used to determine the directory name and modify the
package.json
file. - Receive user input to customize project content (such as selection of frameworks).
- Download the electron-prokit template code locally.
- Give feedback on the creation progress and creation results.
Technical selection
Now that we know the function, we need to make some technical selections. After reading the source code of create-vite, we can also learn from related technical tools.
- Development language tools:
typescript
,ts-node
- Processing command:
commander
- Handle interaction:
inquirer
- Download the git warehouse template:
git-clone
- Semantic template:
handlebars
- Command line beautification:
ora
- File-related plug-ins:
fs-extra
Development steps
Now we will start to talk about how to develop in detail, which is divided into the following 6 steps.
Initialization project
Run from command line
npm i -g pnpm pnpm init
Then add the necessary information, where main is the entry file, and bin is used to introduce a global command, mapped to dist/index.js. With the bin field, we can directly run create-electron-prokit
command, no need for node dist/index.js
anymore.
{<!-- --> "name": "create-electron-prokit", "version": "0.0.1", "description": "A cli to create an electron prokit project", "main": "dist/index.js", "type": "module", "bin": {<!-- --> "create-electron-prokit": "dist/index.js" }, "keywords": [ "Electron", "electron", "electron-prokit", "electron prokit", "Electron Prokit", "Prokit", "prokit", "create-electron-prokit" ], "author": "Xutaotaotao", "license": "MIT", }
Let the project support TS
Install typescript
and @types/node
.
pnpm add typescript @types/node -D
Initialize tsconfig.json
tsc --init
{<!-- --> "compilerOptions": {<!-- --> "target": "es2016", "module": "ESNext", "moduleResolution": "node", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "sourceMap": true, "outDir": "./dist", "importHelpers": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist/**/*"], }
npm link local debugging
Let’s write a hello world in src/index.ts
and test whether ts compilation is normal.
- src/index.ts
#!/usr/bin/env node --experimental-specifier-resolution=node const msg: string = 'Hello World' console.log(msg)
Add the dev
option to the scripts
of the package.json
file
"dev": "node --experimental-specifier-resolution=node --loader ts-node/esm src/index.ts"
Run npm run dev
and you can see that Hello World is half the battle. With the above preparations, we can debug locally. But to achieve the same effect as the command line, npm link
is needed.
Remember we had a bin
configuration in package.json
earlier. If we execute the npm link
command in the project, you can Run the create-electron-prokit
command. But this command points to the file dist/index.js
, which is obviously a compiled file, so we need to add some scripts to
option makes my development smoother!package.json
"scripts": { "dev": "node --experimental-specifier-resolution=node --loader ts-node/esm src/index.ts", "build": "tsc", "start": "node --experimental-specifier-resolution=node dist/index.js" },
npm run build
Then run the create-electron-prokit
command and you will see hello world! Are you very happy? You have completed half of this project. Everything is difficult at the beginning, and the rest is the development of some logical functions.
Command processing function development
Let’s start with the simplest one, receiving command line parameters.
- src/index.ts
#!/usr/bin/env node --experimental-specifier-resolution=node const name = process.argv[2]; if (!name) {<!-- --> log.warn("The project name cannot be empty!"); process.exit(1); } else {<!-- --> init(name); } function init(name: string) {<!-- --> console.log(name) }
It’s that simple. Our first function has been developed. The following is to expand the init
function.
Development of interactive processing functions
At this step we need to print the log, then ask the user for the corresponding opinions, and then obtain the user’s input and selections.
Install inquirer
, ora
, fs-extra
.
pnpm add inquirer ora fs-extra
Added project description and author input query as well as framework selection
#!/usr/bin/env node --experimental-specifier-resolution=node import type {<!-- --> QuestionCollection } from "inquirer"; import inquirer from "inquirer"; import ora from "ora"; import fs from "fs-extra"; const log = ora("modify"); async function init(name: string) {<!-- --> const InitPrompts: QuestionCollection = [ {<!-- --> name: "description", message: "please input description", default: "", }, {<!-- --> name: "author", message: "please input author", default: "", }, ]; const FrameworkOptions: QuestionCollection = {<!-- --> type: "list", name: "framework", message: "Select a framework", choices: [ {<!-- --> name: "React", value: "React", }, {<!-- --> name: "Vue", value: "Vue", }, ], }; if (fs.existsSync(name)) {<!-- --> log.warn(`Has the same name project,please create another project!`); return; } log.info(`Start init create-electron-prokit project: ${<!-- -->name}`); const initOptions = await inquirer.prompt(InitPrompts); const frameworkOptions = await inquirer.prompt(FrameworkOptions); } function main() {<!-- --> const name = process.argv[2]; if (!name) {<!-- --> log.warn("The project name cannot be empty!"); process.exit(1); } else {<!-- --> init(name); } } main()
Here we have optimized and integrated the code to make it clearer. We use ora
to beautify the console output, fs-extra
to detect whether the folder exists, and inquirer
to receive user input and selections. In this step, we obtain the most basic user’s input
, and then download the corresponding template through the user’s input, and then change some template information.
Download template function development
Install git-clone
pnpm add git-clone
Implement download logic in src/download.ts
- src/download.ts
import path from "path" import gitclone from "git-clone" import fs from "fs-extra" import ora from "ora" export const downloadTemplate = ( templateGitUrl: string, downloadPath: string ):Promise<any> => {<!-- --> const loading = ora("Downloadimg template") return new Promise((resolve, reject) => {<!-- --> loading.start("Start download template") gitclone(templateGitUrl, downloadPath, {<!-- --> checkout: "master", shallow: true, },(error:any) => {<!-- --> if (error) {<!-- --> loading.stop() loading.fail("Download fail") reject(error) } else {<!-- --> fs.removeSync(path.join(downloadPath, ".git")) loading.succeed("Download success") loading.stop() resolve("Download success") } }) }) }
Very simple, achieved. Let’s quote it in the init
method and define the corresponding template address.
#!/usr/bin/env node --experimental-specifier-resolution=node import * as tslib from "tslib"; import type {<!-- --> QuestionCollection } from "inquirer"; import inquirer from "inquirer"; import ora from "ora"; import fs from "fs-extra"; import {<!-- --> downloadTemplate } from "./download"; const log = ora("modify"); async function init(name: string) {<!-- --> const ReactTemplateGitUrl = "https://github.com/Xutaotaotao/ep-vite-react-electron-template"; const VueTemplateGitUrl = "https://github.com/Xutaotaotao/ep-vite-vue3-electron-template"; const InitPrompts: QuestionCollection = [ {<!-- --> name: "description", message: "please input description", default: "", }, {<!-- --> name: "author", message: "please input author", default: "", }, ]; const FrameworkOptions: QuestionCollection = {<!-- --> type: "list", name: "framework", message: "Select a framework", choices: [ {<!-- --> name: "React", value: "React", }, {<!-- --> name: "Vue", value: "Vue", }, ], }; if (fs.existsSync(name)) {<!-- --> log.warn(`Has the same name project,please create another project!`); return; } log.info(`Start init create-electron-prokit project: ${<!-- -->name}`); const initOptions = await inquirer.prompt(InitPrompts); const frameworkOptions = await inquirer.prompt(FrameworkOptions); const templateGitUrl = frameworkOptions.framework === "React" ?ReactTemplateGitUrl : VueTemplateGitUrl; try {<!-- --> const downloadPath = `./${<!-- -->name}`; // download await downloadTemplate(templateGitUrl, downloadPath); } catch (error) {<!-- --> console.error(error); } } function main() {<!-- --> const name = process.argv[2]; if (!name) {<!-- --> log.warn("The project name cannot be empty!"); process.exit(1); } else {<!-- --> init(name); } } main()
Wow! We are only one step away from success, which is to modify package.json
.
Modify package.json function development
Before replacing, we need to modify the package.json
of the template and add some slots to facilitate subsequent replacement.
{ "name": "{<!-- -->{name}}", "version": "1.0.0", "description": "{<!-- -->{description}}", "author": "{<!-- -->{author}}" }
Installhandlebars
pnpm add handlebars
Implement modification logic in src/modify.ts
- src/modify.ts
import path from "path" import fs from "fs-extra" import handlebars from "handlebars" import ora from "ora" const log = ora("modify") export const modifyPackageJson = function (downloadPath: string, options: any):void {<!-- --> const packagePath = path.join(downloadPath, "package.json") log.start("start modifying package.json") if (fs.existsSync(packagePath)) {<!-- --> const content = fs.readFileSync(packagePath).toString() const template = handlebars.compile(content) const param = {<!-- --> name: options.name, description: options.description, author: options.author, } const result = template(param) fs.writeFileSync(packagePath, result) log.stop() log.succeed("This project has been successfully created! ") log.info(`Install dependencies: cd ${<!-- -->downloadPath} & amp; & amp; yarn install `) log.info(`Run project: yarn run dev `) } else {<!-- --> log.stop() log.fail("modify package.json fail") throw new Error("no package.json") } }
Here we have completed the function to modify the logic, and then imported and used it in the init
function.
try { const downloadPath = `./${name}`; await downloadTemplate(templateGitUrl, downloadPath); modifyPackageJson(downloadPath, { name, ...initOptions } as Options); } catch (error) { console.error(error); }
OK, here we are done! Next release NPM
Publish NPM
Publishing NPM locally is very simple. There are three steps: build, log in to npm, and then publish
Build
Build and run directly
npm run build
Login & amp;publish
First register an account on the npm official website.
In the project root directory, log in to your npm account and enter your username, password, and email address.
npm login
After successful login, just execute npm publish
directly.
You can read my article on building a Vue UI component library from scratch (3) – releasing the first npm package
Verification
After we publish successfully, we can verify it locally. We can run it directly.
yarn create electron-prokit my-app
or
npm create electron-prokit my-app
You can see the effect!
Conclusion
This article uses the simplest way to build a scaffold. The functions in the middle can actually be enriched, but the core process has been implemented, and subsequent functional expansions are only logical additions and changes, mainly to allow everyone to get started quickly! ! !
Project source code: https://github.com/Xutaotaotao/electron-prokit
If this article is helpful to you, please give a small star to my project?