create-vuepress-theme-hope
Version:
Create vuepress-theme-hope demo project helper
80 lines (69 loc) • 14 kB
JavaScript
import{existsSync as w,readFileSync as y,writeFileSync as v,readdirSync as D,mkdirSync as V,statSync as T,createReadStream as U,createWriteStream as L}from"node:fs";import{resolve as n,join as C,dirname as z}from"node:path";import{select as f,confirm as b,input as k}from"@inquirer/prompts";import{createCommand as K}from"commander";import{execaCommandSync as p,execaCommand as Q}from"execa";import{fileURLToPath as E}from"node:url";const G=["vite","webpack"],M=["blog","docs"],X=()=>{try{return p("pnpm --version",{stdio:"ignore"}).exitCode===0}catch{return!1}},Z=()=>{try{return p("yarn --version",{stdio:"ignore"}).exitCode===0}catch{return!1}},N=["npm"];X()&&N.unshift("pnpm"),Z()&&N.unshift("yarn");const ee=e=>`
node_modules/
${e}/.vuepress/.cache/
${e}/.vuepress/.temp/
${e}/.vuepress/dist/
`,O=(e,t=process.cwd())=>{const o=n(t,".gitignore"),s=w(o)?y(o,{encoding:"utf-8"}):"";v(o,`${s}${ee(e)}`,{encoding:"utf-8"})},te=(e,t,o,{workflow:s})=>`
name: ${s.name}
on:
push:
branches:
- ${p("git branch --show-current",{cwd:t}).stdout.trim()}
permissions:
contents: write
jobs:
deploy-gh-pages:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# ${s.submodule}
# submodules: true
${e==="pnpm"?` - name: ${s.setupPnpm}
uses: pnpm/action-setup@v4
`:""}
- name: ${s.setupNode}
uses: actions/setup-node@v4
with:
node-version: 22
cache: ${e}
- name: ${s.install}
run: |
corepack enable
${e==="npm"?"npm ci":`${e} install --frozen-lockfile`}
- name: ${s.build}
env:
NODE_OPTIONS: --max_old_space_size=8192
run: |-
${e} run docs:build
> ${C(o,".vuepress/dist/.nojekyll").replace(/\\/g,"/")}
- name: ${s.deploy}
uses: JamesIves/github-pages-deploy-action@v4
with:
# ${s.deploy}
branch: gh-pages
folder: ${C(o,".vuepress/dist").replace(/\\/g,"/")}
`,se=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/u,oe=/^[0-9]+\.[0-9]+\.(?:[0-9]+|[0-9]+-[a-z]+\.[0-9])$/u,{isArray:re}=Array,x=e=>Object.prototype.toString.call(e)==="[object Object]",$=(e,...t)=>{if(t.length===0)return e;const o=t.shift();return o&&Object.entries(o).forEach(([s,r])=>{s==="__proto__"||s==="constructor"||(x(e[s])&&x(r)?$(e[s],r):re(r)?e[s]=[...r]:x(r)?e[s]={...r}:e[s]=o[s])}),$(e,...t)},S=e=>{try{D(e)}catch{try{V(e,{recursive:!0})}catch{}}},P=(e,t)=>{const o=z(t);S(o);const s=U(e),r=L(t);s.pipe(r)},q=(e,t)=>{S(t),D(e,{withFileTypes:!0}).forEach(o=>{o.isFile()?P(`${e}/${o.name}`,`${t}/${o.name}`):o.isDirectory()&&q(`${e}/${o.name}`,`${t}/${o.name}`)})},u=(e,t)=>{T(e).isDirectory()?q(e,t):T(e).isFile()&&P(e,t)},ne=(e=process.cwd())=>{try{return p("git status",{cwd:e}),!0}catch{return!1}},ae=()=>{try{return p("git --version"),!0}catch{return!1}},_="https://registry.npmmirror.com/",ie=(e,t)=>p(`${e} config get ${t?"npmRegistryServer":"registry"}`).stdout,ce=async(e,t)=>{const o=e==="yarn"&&!p("yarn --version").stdout.startsWith("1"),s=ie(e,o);return/https:\/\/registry\.npm\.taobao\.org\/?/.test(s)&&(console.error("npm.taobao.org is no longer available, resetting it to npmmirror.com"),p(`${e} config set ${o?"npmRegistryServer":"registry"} ${_}`)),t==="zh"&&await f({message:"选择你想使用的源",choices:["国内镜像源","当前源"].map(r=>({name:r,value:r}))})==="国内镜像源"?_:s},le=E(import.meta.url),g=z(le),A=async({cwd:e=process.cwd(),targetDir:t,lang:o,locale:s,preset:r,packageManager:a})=>{r??=await f({message:s.question.preset,choices:M.map(c=>({name:c,value:c}))});const l=await b({message:s.question.i18n,default:!1});console.log(s.flow.generateTemplate);const i=r;u(n(g,"../template/public"),n(e,t,"./.vuepress/public")),u(n(g,"../template",i,"config/base"),n(e,t,".vuepress")),l?(u(n(g,"../template",i,"en"),n(e,t)),u(n(g,"../template",i,"zh"),n(e,t,"zh")),u(n(g,"../template",i,"config/multi"),n(e,t,".vuepress"))):o==="zh"?(u(n(g,"../template",i,"zh"),n(e,t)),u(n(g,"../template",i,"config/zh"),n(e,t,".vuepress"))):(u(n(g,"../template",i,"en"),n(e,t)),u(n(g,"../template",i,"config/en"),n(e,t,".vuepress")));let d=ne(e);if(d?O(t,e):ae()&&await b({message:s.question.git,default:!0})&&(p("git init -b main",{cwd:e}),O(t,e),d=!0),d&&await b({message:s.question.workflow,default:!0})){const c=n(e,".github/workflows");S(c),v(n(c,"deploy-docs.yml"),te(a,e,t,s),{encoding:"utf-8"})}},h=JSON.parse(y(E(import.meta.resolve("create-vuepress-theme-hope/package.json")),"utf-8")),pe={flow:{getVersion:"Getting latest version of deps...",createPackage:"Generating package.json...",updatePackage:"Updating package.json...",createTsConfig:"Generating tsconfig.json...",updateTsConfig:"Updating tsconfig.json...",generateTemplate:"Generating Template...",install:"Installing Deps...",devServer:`Staring dev server...
After the dev server starts running, please visit the given server link ('localhost:8080' by default)`},question:{i18n:"Does the project need multiple languages?",git:"Initialize a git repository?",workflow:"Do you need a GitHub workflow to deploy docs on GitHub pages?",bundler:"Which bundler do you want to use?",preset:"What type of project do you want to create?",packageManager:"Choose package manager",devServer:"Would you like to preview template now?",name:"Your project name",version:"Your project version",description:"Your project description",license:"Your project license"},hint:{install:`This may take a few minutes, please be patient.
We can not correctly output progress bar from child process, so the process may look stuck.`,finish:"Successful Generated!",devServer:e=>`Hint: You should execute "${e} run docs:dev" to start dev server.`},workflow:{name:"Deploy Docs",checkout:"Checkout code",submodule:"if your docs needs submodules, uncomment the following line",setupPnpm:"Setup pnpm",setupNode:"Setup Node.js",install:"Install Deps",build:"Build Docs",deploy:"Deploy Docs",deployBranch:"This is the branch where the docs are deployed to"},error:{name:"package name should only contain lowercase characters, numbers and dash",version:"This version is not a valid one. Version should be like 'x.x.x'",bundler:'bundler (--bundler) only support "vite" or "webpack"',preset:'preset (--preset) only support "docs" or "blog"',outputDirHint:e=>`The angle brackets in "<dir>" means it is a required argument, you should replace it with folder name you want to use! E.g.: "my-blog", "project-docs"
For example: "${e} init vuepress-theme-hope project-docs"`,addDirHint:e=>`The brackets in "<dir>" means it is a required argument, you should replace it with folder name you want to use! E.g.: "src", "docs"
For example: "${e} init vuepress-theme-hope add docs"`,dirNotEmpty:e=>`Target folder "${e}" is not empty, please choose an empty folder or delete files in it.`}},de={flow:{getVersion:"获取依赖的最新版本...",createPackage:"生成 package.json...",updatePackage:"更新 package.json...",createTsConfig:"生成 tsconfig.json...",updateTsConfig:"更新 tsconfig.json...",generateTemplate:"生成模板...",install:"安装依赖...",devServer:`启动开发服务器...
启动成功后,请在浏览器输入给出的开发服务器地址(默认为 'localhost:8080')`},question:{packageManager:"选择包管理器",i18n:"项目需要用到多语言么?",git:"是否初始化 Git 仓库?",workflow:"是否需要一个自动部署文档到 GitHub Pages 的工作流?",bundler:"你想要使用哪个打包器?",preset:"你想要创建什么类型的项目?",devServer:"是否想要现在启动 Demo 查看?",name:"设置应用名称",version:"设置应用版本号",description:"设置应用描述",license:"设置协议"},hint:{install:`这可能需要数分钟,请耐心等待.
我们无法正确输出子进程的进度条,所以进程可能会看似未响应`,finish:"模板已成功生成!",devServer:e=>`提示: 请使用 "${e} run docs:dev" 命令启动开发服务器`},workflow:{name:"部署文档",checkout:"检出代码",submodule:"如果你文档需要 Git 子模块,取消注释下一行",setupPnpm:"设置 pnpm",setupNode:"设置 Node.js",install:"安装依赖",build:"构建文档",deploy:"部署文档",deployBranch:"这是文档部署到的分支名称"},error:{name:"应用名称应只包含小写字母、数字和连接线 (-)",version:"此版本无效,版本号应为 'x.x.x'",bundler:"打包器 (--bundler) 仅支持 vite 或 webpack",preset:"预设 (--preset) 仅支持 docs 或 blog",outputDirHint:e=>`"<dir>" 的尖括号表示此处为一个必填参数,你应该替换为自己想使用的文件夹名称,如 "my-blog", "project-docs" 等!
例如: "${e} init vuepress-theme-hope project-docs"`,addDirHint:e=>`"<dir>" 的尖括号表示此处为一个必填参数,你应该替换为自己想使用的文件夹名称,如 "src", "docs" 等!
例如: "${e} init vuepress-theme-hope add docs"`,dirNotEmpty:e=>`目标文件夹 "${e}" 不为空,请选择一个空文件夹或者手动删除文件夹中的文件`}},ue={en:pe,zh:de},ge=async()=>{const e=await f({message:"Select a language to display / 选择显示语言",choices:[{name:"English",value:"en"},{name:"简体中文",value:"zh"}]});return{lang:e,locale:ue[e]}},me=(e,t,o)=>({"docs:build":`vuepress-${t} build ${o}`,"docs:clean-dev":`vuepress-${t} dev ${o} --clean-cache`,"docs:dev":`vuepress-${t} dev ${o}`,"docs:update-package":`${e==="npm"?"npx":`${e} dlx`} vp-update`}),H=async({packageManager:e,locale:t,source:o,bundler:s,cwd:r=process.cwd()})=>{s??=await f({message:t.question.bundler,choices:G.map(c=>({name:c,value:c}))});const a=n(r,"package.json"),l=me(e,s,o),i={[`@vuepress/bundler-${s}`]:h.devDependencies.vuepress,"sass-embedded":h.devDependencies["sass-embedded"],...s==="webpack"?{"sass-loader":h.devDependencies["sass-loader"]}:{},vue:h.devDependencies.vue,vuepress:h.devDependencies.vuepress,"vuepress-theme-hope":h.devDependencies["vuepress-theme-hope"]},d={scripts:l,devDependencies:i,...e==="pnpm"?{pnpm:{onlyBuiltDependencies:["esbuild"]}}:{}};if(w(a)){console.log(t.flow.updatePackage);const c=JSON.parse(y(a,{encoding:"utf-8"}));$(c,d),v(a,`${JSON.stringify(c,null,2)}
`,{encoding:"utf-8"})}else{console.log(t.flow.createPackage);const c=await k({message:t.question.name,default:"vuepress-theme-hope-template",validate:j=>se.exec(j)?!0:t.error.name}),W=await k({message:t.question.description,default:"A project of vuepress-theme-hope"}),F=await k({message:t.question.version,default:"2.0.0",validate:j=>oe.exec(j)?!0:t.error.version}),B=await k({message:t.question.license,default:"MIT"}),Y={name:c,description:W,version:F,license:B,type:"module",...d};v(a,`${JSON.stringify(Y,null,2)}
`,{encoding:"utf-8"})}},J=({source:e,locale:t,cwd:o=process.cwd()})=>{const s=n(o,"tsconfig.json");if(w(s)){console.log(t.flow.updateTsConfig);const r=JSON.parse(y(s,{encoding:"utf-8"}));$(r,{compilerOptions:{module:"NodeNext",moduleResolution:"NodeNext"},include:[...r.include??[],`${e}/.vuepress/**/*.ts`,`${e}/.vuepress/**/*.vue`]}),v(s,`${JSON.stringify(r,null,2)}
`,{encoding:"utf-8"})}else{console.log(t.flow.createTsConfig);const r={compilerOptions:{module:"NodeNext",moduleResolution:"NodeNext",target:"ES2022"},include:[`${e}/.vuepress/**/*.ts`,`${e}/.vuepress/**/*.vue`],exclude:["node_modules"]};v(s,`${JSON.stringify(r,null,2)}
`,{encoding:"utf-8"})}},m=K("create-vuepress-theme-hope"),R=async(e,{bundler:t,preset:o,add:s})=>{const{lang:r,locale:a}=await ge();t&&!G.includes(t)&&m.error(a.error.bundler),o&&!M.includes(o)&&m.error(a.error.preset);const l=n(process.cwd(),e);w(l)&&D(l).length&&m.error(a.error.dirNotEmpty(e));const i=await f({message:a.question.packageManager,choices:N.map(d=>({name:d,value:d}))});return e.startsWith("<")&&e.endsWith(">")&&m.error(a.error[s?"addDirHint":"outputDirHint"](i)),S(l),{lang:r,locale:a,packageManager:i}},I=async({cwd:e=process.cwd(),lang:t,locale:o,packageManager:s})=>{const r=s==="pnpm"?"":await ce(s,t);console.log(o.flow.install),console.warn(o.hint.install),p(`${s} install ${r?`--registry ${r}`:""}`,{cwd:e,stdout:"inherit"}),console.log(o.hint.finish),await b({message:o.question.devServer,default:!0})?(console.log(o.flow.devServer),await Q(`${s} run docs:dev`,{cwd:e,stdout:"inherit"})):console.info(o.hint.devServer(s))};m.description(`Generate a new vuepress-theme-hope template
· pnpm create vuepress-theme-hope <dir>
· npm init vuepress-theme-hope@latest <dir>
· yarn create vuepress-theme-hope <dir>
`).option("-b, --bundler [bundler]","Bundler to use, vite or webpack only").option("-p, --preset [preset]","Preset to use, docs or blog only").argument("<dir>","Dir to create the template in").action(async(e,{bundler:t,preset:o})=>{const s=n(process.cwd(),e),{lang:r,locale:a,packageManager:l}=await R(e,{bundler:t,preset:o,add:!1});await H({bundler:t,locale:a,packageManager:l,cwd:e,source:"src"}),J({cwd:e,source:"src",locale:a}),await A({preset:o,lang:r,locale:a,packageManager:l,cwd:s,targetDir:"src"}),await I({lang:r,locale:a,packageManager:l,cwd:s})}),m.command("add").alias("inject").summary("Add template to <dir> inside project").description(`Add vuepress-theme-hope template in <dir> under current project
· pnpm create vuepress-theme-hope add <dir>
· npm init vuepress-theme-hope@latest add <dir>
· yarn create vuepress-theme-hope add <dir>
`).usage("").option("-b, --bundler [bundler]","Choose bundler to use").option("-p, --preset [preset]","Choose preset to use").argument("<dir>","Dir to create the template in").action(async(e,{bundler:t,preset:o})=>{const{lang:s,locale:r,packageManager:a}=await R(e,{bundler:t,preset:o,add:!0});await H({bundler:t,packageManager:a,locale:r,source:e}),J({source:e,locale:r}),await A({packageManager:a,lang:s,locale:r,preset:o,targetDir:e}),await I({lang:s,locale:r,packageManager:a})}),m.version(h.version),m.showHelpAfterError("add --help for additional information"),await m.parseAsync();