나만의 프로젝트 템플릿 생성기 만들기
12405 단어 npmjavascriptnodetypescript
나만의 템플릿 생성기를 만들고 싶은 이유는 무엇입니까?
때때로 새 프로젝트를 만들고 싶지만 이전에 설정한 것을 기반으로 합니다. React with Node가 필요하지만 이전 프로젝트에서 모든 것을 구현한 방법을 잊어버렸기 때문에 이전 프로젝트를 통해 소싱하는 대신 템플릿을 만들어 이 템플릿 생성기에서 사용하는 것이 어떻습니까?
건너뛰고 직접 구축하지 않으려면 여기에서 Project Template Generator에 대한 저장소를 참조하십시오.
시작하자
1. 새 TypeScript 프로젝트 만들기
1. create a new project folder (mkdir PROJECT_NAME & cd PROJECT NAME)
2. run npm init (to initialize a new node project)
3. run npm add -D typescript ts-node nodemon
- ts-node is used to run typescript without compiling
- nodemon is used to run/restart node automatically when files changed
4. run npx tsc --init
5. adjust tsconfig.json to the following
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"declaration": true,
"sourceMap": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
}
}
6. create folder src and index.ts file
2. 기본 템플릿 생성기 프로젝트에 sample-project 추가
1. create a the following folder tree inside your project: src/templates/sample-project.
2. inside the sample-projects folder create a package.json file that contains the following:
{
"name": "sample-project",
"version": "1.0.0",
"license": "MIT"
}
이제 구조는 다음과 같아야 합니다.
3. "src/index.ts" 상단에 다음을 추가합니다.
1. #!/usr/bin/env node
This is known as "shebang" this tells node to run the typescript code.
4. 이제 CLI에서 템플릿 폴더를 선택 항목으로 읽을 수 있습니다.
1. run npm add -D @types/node @types/inquirer
2. run npm add inquirer
3. update src/index.ts
import * as fs from 'fs';
import * as path from 'path';
import * as inquirer from 'inquirer';
import chalk from 'chalk';
const CHOICES = fs.readdirSync(path.join(__dirname, 'templates'));
const QUESTIONS = [
{
name: 'template',
type: 'list',
message: 'What project template would you like to use?',
choices: CHOICES
},
{
name: 'name',
type: 'input',
message: 'New project name?'
}];
inquirer.prompt(QUESTIONS)
.then(answers => {
console.log(answers);
});
4. to test update package.json script
"scripts": {
"start": "ts-node src/index.ts"
}
and run npm start
src/templates에 자신의 템플릿을 추가하면 목록에 더 많은 템플릿이 있습니다.
5. 입력 옵션 사용
1. update src/index.ts with the following
2. export interface CliOptions {
projectName: string
templateName: string
templatePath: string
tartgetPath: string
}
const CURR_DIR = process.cwd();
inquirer.prompt(QUESTIONS)
.then(answers => {
const projectChoice = answers['template'];
const projectName = answers['name'];
const templatePath = path.join(__dirname, 'templates', projectChoice);
const tartgetPath = path.join(CURR_DIR, projectName);
const options: CliOptions = {
projectName,
templateName: projectChoice,
templatePath,
tartgetPath
}
console.log(options);
});
6. 프로젝트 폴더 생성
질문에서 새 프로젝트 이름? 루트 디렉터리에 새 폴더 "projectName"을 만듭니다.
function createProject(projectPath: string) {
if (fs.existsSync(projectPath)) {
console.log(chalk.red(`Folder ${projectPath} exists. Delete or use another name.`));
return false;
}
fs.mkdirSync(projectPath);
return true;
}
실패시 기능 정지
inquirer.prompt(QUESTIONS)
.then(answers => {
....
if (!createProject(tartgetPath)) {
return;
}
});
7. 선택한 템플릿에서 새 프로젝트로 파일 및 폴더 복사
1. Add to src/index.ts
2. // list of file/folder that should not be copied
const SKIP_FILES = ['node_modules', '.template.json'];
function createDirectoryContents(templatePath: string, projectName: string) {
// read all files/folders (1 level) from template folder
const filesToCreate = fs.readdirSync(templatePath);
// loop each file/folder
filesToCreate.forEach(file => {
const origFilePath = path.join(templatePath, file);
// get stats about the current file
const stats = fs.statSync(origFilePath);
// skip files that should not be copied
if (SKIP_FILES.indexOf(file) > -1) return;
if (stats.isFile()) {
// read file content and transform it using template engine
let contents = fs.readFileSync(origFilePath, 'utf8');
// write file to destination folder
const writePath = path.join(CURR_DIR, projectName, file);
fs.writeFileSync(writePath, contents, 'utf8');
} else if (stats.isDirectory()) {
// create folder in destination folder
fs.mkdirSync(path.join(CURR_DIR, projectName, file));
// copy files/folder inside current folder recursively
createDirectoryContents(path.join(templatePath, file),
path.join(projectName, file));
}
});
}
템플릿을 만든 후 다음 코드를 추가합니다.
....
if (!createProject(tartgetPath)) {
return;
}
createDirectoryContents(templatePath, projectName);
....
8. 프로그램을 CLI로 테스트하기
스크립트 작성을 위한 도구 "shx"설치
1. Run npm add -D shx
2. Add the following build script to package.json
"build": "tsc && shx rm -rf dist/templates && shx cp -r src/templates dist"
3. npm run build
4. Add bin to package.json
"bin": {
"template-generator": "./dist/index.js"
}
5. Register "template-generator" as a command line interface
run npm link
성공하면 시스템의 어느 곳에서나 "템플릿 생성기"명령을 실행할 수 있습니다. (파일 읽기/쓰기 권한이 있는지 확인하십시오.)
9. 마지막 단계: 입력으로 생성된 새 프로젝트로 프로젝트 이름 바꾸기
이제 주어진 질문 목록에서 템플릿을 선택한 다음 새 프로젝트 이름을 입력할 수 있지만 복사되는 템플릿 파일은 새 package.json의 프로젝트 이름과 정확히 동일하며 이를 자동화하려고 합니다.
1. update template "src/templates/sample-project/package.json" with a placholder name
{
"name": "<%= projectName %>",
"version": "1.0.0",
....
}
2. npm add ejs
add -D @types/ejs
3. update src/utils/template.ts to render template under utils
import * as ejs from 'ejs';
export interface TemplateData {
projectName: string
}
export function render(content: string, data: TemplateData) {
return ejs.render(content, data);
}
4. Add code to transform the content inside "src/index.ts" function "createDirectoryContents"
if (stats.isFile()) {
// read file content and transform it using template engine
let contents = fs.readFileSync(origFilePath, 'utf8');
contents = template.render(contents, { projectName });
}
5. run npm build and then generate-template to test that the new project name is inserted in the "<%= projectName %>" placeholder.
이제 프로젝트 템플릿 생성기가 완료되었습니다.
여기에 뭔가 놓친 경우를 대비하여 전체 src/index.ts 파일이 있습니다.
#!/usr/bin/env node
import * as fs from 'fs';
import * as path from 'path';
import * as inquirer from 'inquirer';
import chalk from 'chalk';
import * as template from './utils/template';
import * as shell from 'shelljs';
const CHOICES = fs.readdirSync(path.join(__dirname, 'templates'));
const QUESTIONS = [
{
name: 'template',
type: 'list',
message: 'What template would you like to use?',
choices: CHOICES
},
{
name: 'name',
type: 'input',
message: 'Please input a new project name:'
}];
export interface CliOptions {
projectName: string
templateName: string
templatePath: string
tartgetPath: string
}
const CURR_DIR = process.cwd();
inquirer.prompt(QUESTIONS).then(answers => {
const projectChoice = answers['template'];
const projectName = answers['name'];
//@ts-ignore
const templatePath = path.join(__dirname, 'templates', projectChoice);
//@ts-ignore
const tartgetPath = path.join(CURR_DIR, projectName);
const options: CliOptions = {
//@ts-ignore
projectName,
//@ts-ignore
templateName: projectChoice,
templatePath,
tartgetPath
}
if (!createProject(tartgetPath)) {
return;
}
//@ts-ignore
createDirectoryContents(templatePath, projectName);
postProcess(options);
});
function createProject(projectPath: string) {
if (fs.existsSync(projectPath)) {
console.log(chalk.red(`Folder ${projectPath} exists. Delete or use another name.`));
return false;
}
fs.mkdirSync(projectPath);
return true;
}
const SKIP_FILES = ['node_modules', '.template.json'];
function createDirectoryContents(templatePath: string, projectName: string) {
// read all files/folders (1 level) from template folder
const filesToCreate = fs.readdirSync(templatePath);
// loop each file/folder
filesToCreate.forEach(file => {
const origFilePath = path.join(templatePath, file);
// get stats about the current file
const stats = fs.statSync(origFilePath);
// skip files that should not be copied
if (SKIP_FILES.indexOf(file) > -1) return;
if (stats.isFile()) {
// read file content and transform it using template engine
let contents = fs.readFileSync(origFilePath, 'utf8');
contents = template.render(contents, { projectName });
// write file to destination folder
const writePath = path.join(CURR_DIR, projectName, file);
fs.writeFileSync(writePath, contents, 'utf8');
} else if (stats.isDirectory()) {
// create folder in destination folder
fs.mkdirSync(path.join(CURR_DIR, projectName, file));
// copy files/folder inside current folder recursively
createDirectoryContents(path.join(templatePath, file), path.join(projectName, file));
}
});
}
function postProcess(options: CliOptions) {
const isNode = fs.existsSync(path.join(options.templatePath, 'package.json'));
if (isNode) {
shell.cd(options.tartgetPath);
const result = shell.exec('npm install');
if (result.code !== 0) {
return false;
}
}
return true;
}
및 사용할 전체 프로젝트에 대한 링크: Project Template Generator
Reference
이 문제에 관하여(나만의 프로젝트 템플릿 생성기 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/duwainevandriel/build-your-own-project-template-generator-59k4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)