当前位置: 首页 > news >正文

建一个网站流程青岛软件开发公司有哪些

建一个网站流程,青岛软件开发公司有哪些,长宁房产网站建设,网站建设与维护前段时间阅读了 https://juejin.cn/post/7260144602471776311#heading-25 这篇文章#xff1b;本文做一个梳理和笔记#xff1b; 主要聚焦的知识点如下#xff1a; 如何搭建脚手架工程如何开发调试如何处理命令行参数如何实现用户交互如何拷贝文件夹或文件如何动态生成文件…前段时间阅读了 https://juejin.cn/post/7260144602471776311#heading-25 这篇文章本文做一个梳理和笔记 主要聚焦的知识点如下 如何搭建脚手架工程如何开发调试如何处理命令行参数如何实现用户交互如何拷贝文件夹或文件如何动态生成文件如何处理路径如何自动安装依赖 step1初始化工程 推荐使用pnpm搭建mono-repo风格的工程 mono-repo工程可以包含多个子工程并且每个子工程都可以独立编译打包并将打包的产物发成npm包 这样在同一个工程中我们可以写库也可以写demo 步骤如下 执行 pnpm init 命令生成package.json文件新建 pnpm-workspace.yaml 文件添加如下配置 packages: - packages/* - demos/* 配置后声明了 packages 和 demos 文件夹中子工程是同属一个工作空间的工作空间中的子工程编译打包的产物都可以被其它子工程引用。 在packages文件夹下 新建zy-cli文件夹cd 到 zy-cli文件夹下运行 pnpm init 初始化zy-cli 下的 packages.json 中声明 bin 命令 zy-script bin: {zy-script: ./bin/index.js}, 添加 bin文件夹添加index.js文件写入如下代码 #!/usr/bin/env node console.log(hellow, zy-cli); demos 文件夹中存放使用脚手架的演示项目我们先建一个app文件夹执行 pnpm init 命令生成package.json文件在app中依赖 zy/zy-cli ( 此处依赖名称与zy-cli 的package.json 中 name一致 ) pnpm add zy/zy-cli -F app 会在dependencies自动添加依赖 并添加script指令 zy 与zy-cli中声明的指令一致 scripts: {zy: zy-script},dependencies: {zy/zy-cli: workspace:^}, 执行pnpm -i 安装依赖 在app目录下运行pnpm zy成功输出了 hellow, zy-cli 小节 到目前为止我们成功创建了mono-repo风格的项目结构 packages zy-cli 是我们脚手架工程在bin中自定义了指令 demos app 是使用 zy-cli 脚手架的示例工程利用pnpm的workspace指定了工作区中zy-cli依赖在script中自定义使用 zy-cli中声明的命令 整个工程结构如下 |-- my-cli|-- package.json|-- pnpm-lock.yaml|-- pnpm-workspace.yaml|-- demos| |-- app| |-- package.json|-- packages|-- zy-cli|-- package.json|-- bin|-- index.js现在我们思考一下一个脚手架工程需要哪些模块 命令参数模块用户交互模块文件拷贝模块动态文件生成模块自动安装依赖模块 接下来我们一步一步实现他们 step2命令参数模块 当我们执行命令的时候经常会带一些参数如何获取并利用这些参数 nodeJS 中 process 模块可以获取当前进程相关的全局环境信息 - 命令行参数环境变量命令运行路径等 利用 progress.argv 获取 const process require(process); // 获取命令参数 console.log(process.argv); 或者可以采用更便捷的方案 yargs 开源库 我们为zy-cli 安装 yargs pnpm add yargs --F zy-cli 注意--F zy-cli 指的是指定给该工程安装-W 是全局安装的意思 我们在zy-cli - bin - index.js 中写入如下测试代码 #!/usr/bin/env node // 此处遵循CommonJS规范 const yargs require(yargs);console.log(name, yargs.argv.name);在demos - app 目录下执行 pnpm zy --namezhang 打印输出如下 step3创建子命令 我们在使用vue-cli的时候都用过 vue creat app 之类的命令creat就是子命令 我们通过 yarg.command 来实现 yargs.command(cmd, desc, builder, handler) cmd字符串子命令名称也可以传递数组如 [create, c]表示子命令叫 create其别名是 cdesc字符串子命令描述信息builder子命令参数信息配置比如可以设置参数builder也可以是一个函数 alias别名demand是否必填default默认值describe描述信息type参数类型string | boolean | number。 handler: 函数可以在这个函数中专门处理该子命令参数。 下面我们定义一个creat命令 #!/usr/bin/env node const yargs require(yargs); console.log(name, yargs.argv.name); yargs.command({// 字符串子命令名称也可以传递数组如 [create, c]表示子命令叫 create其别名是 ccommand: create name,// 字符串子命令描述信息describe: create a new project,// 对象子命令的配置项builder也可以是一个函数builder: {name: {alias: n, // 别名demandOption: true, // 是否必填describe: name of a project, // 描述default: app // 默认}},// 函数形式的// builder: (yargs) {// return yargs.option(name, {// alias: n,// demand: true,// describe: name of a project,// type: string// })// },handler: (argv) {console.log(argv, argv);} }); 我们运行一下这个命令pnpm zy create my-app 输出如下 step4增加用户交互 当我们使用vue create xxx 的时候命令行会出现选项式的交互让我们选择配置 这里我们也实现一下使用 inquirer 库 运行命令安装 pnpm add inquirer8.2.5 --F zy-cli inquirer主要做了三件事情 询问用户问题获取用户输入校验用户输入 const inquirer require(inquirer);function inquirerPrompt(argv) {// 先获取到了命令行中的nameconst { name } argv;return new Promise((resolve, reject) {inquirer.prompt([{type: input,name: name,message: 模板名称,default: name,validate: function (val) {if (!/^[a-zA-Z]$/.test(val)) {return 模板名称只能含有英文;}if (!/^[A-Z]/.test(val)) {return 模板名称首字母必须大写}return true;},},{type: list,name: type,message: 模板类型,choices: [表单, 动态表单, 嵌套表单],filter: function (value) {return {表单: form,动态表单: dynamicForm,嵌套表单: nestedForm,}[value];},},{type: list,message: 使用什么框架开发,choices: [react, vue],name: frame,}]).then(answers {const { frame } answers;if (frame react) {inquirer.prompt([{type: list,message: 使用什么UI组件库开发,choices: [Ant Design,],name: library,}]).then(answers1 {resolve({...answers,...answers1,})}).catch(error {reject(error)})}if (frame vue) {inquirer.prompt([{type: list,message: 使用什么UI组件库开发,choices: [ Element],name: library,}]).then(answers2 {resolve({...answers,...answers2,})}).catch(error {reject(error)})}}).catch(error {reject(error)})})}exports.inquirerPrompt inquirerPrompt; 其中 inquirer.prompt() 返回的是一个 Promise我们可以用 then 获取上个询问的答案根据答案再发起对应的内容。 在index.js 中引入并使用 #!/usr/bin/env nodeconst yargs require(yargs); const { inquirerPrompt } require(./inquirer);// 命令配置 yargs.command({// 字符串子命令名称也可以传递数组如 [create, c]表示子命令叫 create其别名是 ccommand: create name,// 字符串子命令描述信息describe: create a new project,// 对象子命令的配置项builder也可以是一个函数builder: {name: {alias: n, // 别名demandOption: true, // 是否必填describe: name of a project, // 描述default: app // 默认}},// 函数形式的// builder: (yargs) {// return yargs.option(name, {// alias: n,// demand: true,// describe: name of a project,// type: string// })// },handler: (argv) {inquirerPrompt(argv).then((answers) {console.log(answers);});} }).argv; 我们运行 pnpm zy create my-app 试试 step5文件夹拷贝 前几节我们实现了一个可以读取命令行的cli工程配置 接下来我们就要深入到cli脚手架的构建 首先是文件夹的拷贝。我们使用 copy-dir 库来实现文件夹拷贝 安装pnpm add copy-dir --F zy-cli bin中创建copy.js实现简单的copy函数check函数 const copydir require(copy-dir) const fs require(fs);function copyDir (from, to, option) {copydir.sync(from, to, option); }/*** Checks if a directory or file exists at the given path.* param {string} path - The path to check for existence.* returns {boolean} - Returns true if the directory or file exists, false otherwise.*/ function checkMkdirExists(path){return fs.existsSync(path); }exports.copyDir copyDir; exports.checkMkdirExists checkMkdirExists; 这几个函数比较简单但是主要难点在于使用具体来说就是 fromto参数 先定个需求我们运行 creat 选择 form类型 命令的时候需要将 zy-cli src form 文件夹拷贝到 demos app src app-name 中 我们分析一下如何获取当前模板的位置也就是 copyDir 的 from 参数 __dirname 是用来动态获取当前文件模块所属目录的绝对路径。比如在 bin/index.js 文件中使用 __dirname __dirname 表示就是 bin/index.js 文件所属目录的绝对路径 ~/Desktop/my-cli/zy-cli/bin。 使用 path.resolve( [from…], to )将相对路径转成绝对路径 那我们模板的路径就是path.resolve( __dirname../src/form )或者path.resolve( __dirname../src/${type}) 接下来我们确定 copyDir 的 to 参数也就是目标文件夹 app-name 我们运行脚手架命令是在 app 目录下pnpm zy 执行的是 app packages.json 所以在node脚本中可以使用 process.cwd() 获取文件路径 那我们拷贝的目标路径就是path.resolve(process.cwd(), ./src/${app-name}) handler: (argv) {inquirerPrompt(argv).then((answers) {// 此处已经获取到了完整的模版参数;开始进行文件处理const { name, type, frame, library } answers;// 判断是否存在该项目文件夹const isMkdirExists checkMkdirExists(path.resolve(process.cwd(),./${name}));if (isMkdirExists) {console.log( ${name}文件夹已经存在);} else {const templatePath path.resolve(__dirname, ../src/${type});const targetPath path.resolve(process.cwd(), ./${name});copyDir(templatePath, targetPath);}});} 运行一下命令pnpm zy create my-app选择表单类型回车拷贝成功 step6目录守卫 如果我需要将文件拷贝到 app pages name 下由于没有pages目录命令会报错 我们简单实现一个目录守卫帮我们创建不存在的目录 const copydir require(copy-dir) const fs require(fs);function copyDir (from, to, option) {// 目录守卫,不存在的目录结构会去创建mkdirGuard(to);copydir.sync(from, to, option); }/*** Checks if a directory or file exists at the given path.* param {string} path - The path to check for existence.* returns {boolean} - Returns true if the directory or file exists, false otherwise.*/ function checkMkdirExists(path){return fs.existsSync(path); }// 目录守卫 function mkdirGuard(target) {try {fs.mkdirSync(target, { recursive: true });} catch (e) {mkdirp(target)function mkdirp(dir) {if (fs.existsSync(dir)) { return true }const dirname path.dirname(dir);mkdirp(dirname);fs.mkdirSync(dir);}} }exports.copyDir copyDir; exports.checkMkdirExists checkMkdirExists; exports.mkdirGuard mkdirGuard; step7文件拷贝 文件操作主要使用 fs.readFileSync 读取被拷贝的文件内容然后创建一个文件再使用 fs.writeFileSync 写入文件内容这两个api都是比较熟悉的老朋友了不做过多介绍 我们定义一个 copyFile函数 function copyFile(from, to) {const buffer fs.readFileSync(from);const parentPath path.dirname(to);mkdirGuard(parentPath)fs.writeFileSync(to, buffer); }exports.copyFile copyFile;使用方法与copyDir 类似只不过需要精确到文件这里就不演示了 step8动态文件生成 我们在定义脚手架的时候会获取很多类型的命令参数有些参数可能对我们模板文件产生影响。 例如根据命令行中的name动态修改packages中的name 这里我们需要依赖 mustache 安装pnpm add mustache --F zy-cli 我们增加一个 renderTemplate 函数 接受动态模板的path路径data动态模版的配置数据 Mustache.render(str, data) 接受动态模版和配置数据 Mustache.render(span{{name}}/span,{name:张三}) const Mustache require(mustache); function renderTemplate(path, data {}) {const str fs.readFileSync(path, { encoding: utf8 })return Mustache.render(str, data); } exports.renderTemplate renderTemplate; 再定义一个copyTemplate 函数 path.extname 获取文件扩展名如果不是tpl类型的直接当做文件处理 function copyTemplate(from, to, data {}) {if (path.extname(from) ! .tpl) {return copyFile(from, to);}const parentToPath path.dirname(to);// 目录守卫mkdirGuard(parentToPath);// 写入文件fs.writeFileSync(to, renderTemplate(from, data)); } 在index.js中试验一下 const templatePath path.resolve(__dirname, ../src/${type}/packages.tpl); const targetPath path.resolve(process.cwd(), ./${name}/packages.json); copyTemplate(templatePath, targetPath, {name: name}) {name: {{name}},version: 1.0.0,description: ,main: index.js,scripts: {},keywords: [],author: ,license: ISC }运行完创建命令后成功生成packages.json 文件并且将 name字段替换成功 扩展mustache 一些用法补充 基础绑定 Mustache.render(span{{name}}/span,{name:张三}) 绑定子属性 Mustache.render(span{{ifno.name}}/span, { ifno: { name: 张三 } }) 循环渲染 // {{#key}} {{/key}} 开启和结束循环 Mustache.render(span{{#list}}{{name}}{{/list}}/span,{list: [{ name: 张三 },{ name: 李四 },{ name: 王五 },]} ) 循环渲染 二次处理 Mustache.render(span{{#list}}{{info}}{{/list}}/span,{list: [{ name: 张三 },{ name: 李四 },{ name: 王五 },],info() {return this.name ,;}} ) 条件渲染 // 使用 {{#key}} {{/key}} 语法 和 {{^key}} {{/key}} 语法来实现条件渲染 // 当 key 为 false、0、[]、{}、null既是 key false 为真 // {{#key}} {{/key}} 包裹的内容不渲染 // {{^key}} {{/key}} 包裹的内容渲染 Mustache.render(span{{#show}}显示{{/show}}{{^show}}隐藏{{/show}}/span,{show: false} ) step9实现自动安装依赖 我们在选择完框架和UI库的时候可以帮助目标项目自动安装依赖 我们使用 node 中提供的 child_process 子进程来实现 child_process.exec(command, options, callback) command命令比如 pnpm installoptions参数 cwd设置命令运行环境的路径env环境变量timeout运行执行现在 callback运行命令结束回调(error, stdout, stderr) { }执行成功后 error 为 null执行失败后 error 为 Error 实例stdout、stderr 为标准输出、标准错误其格式默认是字符串。 我们定义一个 manager 函数 const path require(path); const { exec } require(child_process);// 组件库映射,前面是用户输入/选择,后面是目标安装的组件库 const LibraryMap {Ant Design: antd,iView: view-ui-plus,Ant Design Vue: ant-design-vue,Element: element-plus, }function install(cmdPath, options) {// 用户选择的框架 和 组件库const { frame, library } options;// 安装命令const command pnpm add ${frame} pnpm add ${LibraryMap[library]}return new Promise(function (resolve, reject) {// 执行安装命令exec(command,{// 命令执行的目录cwd: path.resolve(cmdPath),},function (error, stdout, stderr) {console.log(error, error);console.log(stdout, stdout);console.log(stderr, stderr)})}) } exports.install install; 使用 // 传入当前进程的目录以及用户选择的配置 install(process.cwd(), answers) 试验一下pnpm create xxxx成功安装 但是安装过程没有进度展示我们使用 ora 来丰富安装加载动画 安装pnpm add ora5.4.1 --F zy-cli 使用 const path require(path); const { exec } require(child_process); const ora require(ora);// 组件库映射,前面是用户输入/选择,后面是目标安装的组件库 const LibraryMap {Ant Design: antd,iView: view-ui-plus,Ant Design Vue: ant-design-vue,Element: element-plus, }function install(cmdPath, options) {// 用户选择的框架 和 组件库const { frame, library } options;// 串行安装命令const command pnpm add ${frame} pnpm add ${LibraryMap[library]}return new Promise(function (resolve, reject) {const spinner ora();spinner.start(正在安装依赖请稍等);// 执行安装命令exec(command,{// 命令执行的目录cwd: path.resolve(cmdPath),},function (error) {if (error) {reject();spinner.fail(依赖安装失败);return;}spinner.succeed(依赖安装成功);resolve()})}) } exports.install install; 再次执行已经有状态提示了 step10推送到私有npm仓库 使用verdaccio搭建私有npm仓库的步骤本文不赘述可以参考这篇文章搭建自己的私有npm库 // TODO 部署过程中使用docker-compose遇到一些问题预计单独开一篇文章去记录 假设我们已经有了npm私库iphttp://xxxxxx:4873/ 我们使用 nrm 去管理 npm 的仓库地址 // 全局安装 npm install -g nrm// 查看所有的仓库 nrm ls // 切换仓库 nrm use name // 添加仓库 nrm add name address 推送之前我们需要修改 packages.json 中的信息 {name: zy/zy-cli,version: 1.0.0,description: ,main: index.js,bin: {zy-script: ./bin/index.js},scripts: {test: echo \Error: no test specified\ exit 1},// 规定上传到npm包中的文件files: [bin,src],keywords: [],author: ,license: ISC,dependencies: {copy-dir: ^1.3.0,inquirer: 8.2.5,mustache: ^4.2.0,ora: 5.4.1,yargs: ^17.7.2} } 推送 pnpm publish --registry http://xxxxx:4873/ 刷新我们的 vedaccio已经存在这个包了 使用 我们在Desktop中新建一个空白文件夹 mkdir cli-test cd cli-test pnpm init nrm use zy pnpm i zy/zy-cli 此时我们的cli-test项目已经成功安装了私有npm仓库的 zy-cli 项目 在packages.json 中添加命令 scripts: {zy-script: zy-script}, 执行 pnpm zy-script create Myapp 成功安装所有依赖并拷贝文件 总结 我们搭建了一个mono-repo风格的工程包含了一个zy-cli脚手架工程和demos-app的测试工程zy-cli实现了用户交互式的命令行命令行参数获取文件拷贝动态文件生成自动安装依赖我们将zy-cli推送到了npm私有仓库上并另开了一个工程切换私库源成功安装并且运行 展望 目前初步实现了mono-repo工程还需要添加统一的publish脚本包含版本自增等 cli 脚手架不需要打包所以还需要为这个工程添加一个 组件库工具函数库等类型的包
http://www.w-s-a.com/news/966442/

相关文章:

  • 网站开发的论文题目广告设计排行榜
  • 网络营销网站 功能南京h5制作公司
  • 做网站的费用的会计分录合肥做网站推广哪家好
  • 电子商城网站开发怎么wordpress用的什么主题
  • 榆林电商网站建设网上做试卷的网站
  • 文山网站建设代理中公教育培训机构官网
  • 郑州it培训机构有哪些上海外贸网站seo
  • dw做网站的实用特效广东住房与城乡建设厅网站
  • 模板网站 动易哪方面的网站
  • 怎么给网站做外链邵连虎郑州做网页的公司
  • 重庆网站开发哪家好宁波网站建设caiyiduo
  • 手机网站建设价格手机网站模版更换技巧
  • 哈尔滨松北区建设局网站美妆网站建设
  • 不需要网站备案的空间网站推广的基本方法是哪四个
  • 如何检查网站死链劳动仲裁院内部网站建设
  • 江西省住房和城乡建设网站合同管理系统
  • 网站建设质量保证福州网络推广
  • 高唐网站建设公司广州南站在哪个区
  • 广西柳州网站制作公司郴州网红打卡景点
  • 做网站要固定ip拍摄公司宣传片制作
  • 专业微网站电话号码做软件难吗
  • 邢台网站制作哪家强上海做网站设计
  • 大连网站建设外贸wordpress添加文章属性
  • 商城网站建设合同范本网上哪里可以免费学编程
  • 服务器公司网站博客wordpress怎么编辑
  • 网站建设网络推广柯西乡塘网站建设
  • 企业做网站需要多少钱企业资质查询系统官网
  • 网站建设需要知识百度统计数据
  • 自已如何做网站建设通网站会员共享密码
  • 做网站学习什么wordpress 文件夹