-
Notifications
You must be signed in to change notification settings - Fork 0
/
search_plus_index.json
1 lines (1 loc) · 86.4 KB
/
search_plus_index.json
1
{"./":{"url":"./","title":"Introduction","keywords":"","body":"Web 前端架构师课 - 学习笔记 浅层学习看输入,深入学习看输出! 慕课网《Web 前端架构师》课程学习笔记汇总,课程要求每位同学每周都要及时产出学习笔记。 精选学习笔记 【郭二蛋】第一周笔记和作业 【点点】需求分析和架构设计 【彩笔】架构方案设计文档 【yhtx1997】第一周作业 【郭二蛋】第二周笔记和作业 【六玥】第二周笔记和作业 【彩笔】脚手架架构设计和框架搭建 【Berners】第二周笔记和作业 【い狂奔的蜗牛】01.Node.js中经典算法(一) 【yhtx1997】02-第二周作业 【郭二蛋】03-第三周学习笔记 【い狂奔的蜗牛】02.Node.js中使用ES Module的两种方式 【彩笔】作业-03-脚手架核心流程开发 【Berners】03-第三周笔记和作业 【clqyfe】07-Week03-脚手架核心流程开发 【彩笔】作业-04-脚手架命令注册和执行过程开发 【い狂奔的蜗牛】03.sim-cli核心图集 【い狂奔的蜗牛】04.Node.js多进程源码分析 【郭二蛋】04-第四周笔记 【い狂奔的蜗牛】07.第五周-readline源码阅读及实现简易版readline 【い狂奔的蜗牛】08.第五周-类似inquirer列表类型交互实现 【Sunshine】第五周笔记和作业 【彩笔】作业-05-脚手架创建项目流程设计和开发 【い狂奔的蜗牛】09.第六周-ejs源码分析 【jolly_chen】第六周 ejs使用和源码解析 【jolly_chen】第六周 node require 加载模块.md 【い狂奔的蜗牛】10.第六周-require源码分析 【彩笔】作业-06-脚手架项目和组件初始化开发 提交你的学习笔记 注意,以下操作需要你了解 github 的 fork 和 pull request 机制。这也是多人协作开发所必备的技能。 fork 源码 进入 https://github.com/psybor/students-learn-task ,fork 项目到自己的 github 空间。 然后下载项目到本地,安装并启动。 cd students-learn-task npm i npm run dev # 访问 localhost:4000 写学习笔记 即写博客文章。注意,全程使用 markdown 语法,不懂的自己去查。 新建 docs/pages// 目录 , 即你在慕课网的用户名(或昵称、网名,都可以) 新建 docs/pages//README.md ,内容参考现有的 docs/pages/双越老师/README.md 在 docs/pages// 下新建博客文件,命名格式按照 01-xxx.md 02-yyy.md 03-zzz.md ... 一定以序号 01- 02- 开头!! 如果需要图片,可把图片文件放在 docs/pages//images/ 中,然后在博客中引入 删掉 docs/SUMMARY.md 你在本地执行 npm run dev 或 npm run build 都会自动生成 docs/SUMMARY.md 。 检查一下,如果你的代码中有 docs/SUMMARY.md 这个文件,请删除掉它。 否则,可能会和别人产生冲突,请一定注意检查!!! 最后,提交代码到 github 。 提交 pull request 从你 fork 的仓库,提交 pull request 到 https://github.com/psybor/students-learn-task ,请求合并到 main 分支 确定 https://github.com/psybor/students-learn-task 有你提交的 pull request 等待讲师处理(一般会在 24h 之内处理:合并或者回复),注意看 github 的通知 自动发布 pull request 被合并之后,会触发 github actions ,自动打包、发布到 http://homework.imooc-lego.com/ 。 过程大概 3-5 分钟。 重点提醒 第一次,记得新建 docs/pages//README.md 文件 图片文件都放在 docs/pages//images/ 目录中 提交时记得删掉 docs/SUMMARY.md 文件,否则容易产生冲突 Pull request 提交成功之后,自己再检查一下:看是否有冲突?看 Files changed 是否符合预期? Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/Baran/":{"url":"pages/Baran/","title":"Baran","keywords":"","body":"Baran - 作业 浅层学习看输入,深层学习看输出💪💪💪 第一周 01-需求分析和架构设计 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/Baran/01-需求分析和架构设计.html":{"url":"pages/Baran/01-需求分析和架构设计.html","title":"需求分析和架构设计","keywords":"","body":"需求分析和架构设计 第3章 需求分析 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/zy/":{"url":"pages/zy/","title":"Zy","keywords":"","body":"zy - 作业 浅层学习看输入,深层学习看输出💪💪💪 第一周 01-需求分析和架构设计第二周 02-脚手架分析 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/zy/01-需求分析和架构设计.html":{"url":"pages/zy/01-需求分析和架构设计.html","title":"需求分析和架构设计","keywords":"","body":"01-需求分析和架构设计 需求 范围 普通用户使用的 H5 端(C 端) 使用者和用途:普通用户,也就是作品的受众,可以对作品分享。促进业务增长。 开发方式:H5 SSR 企业、作者使用的 B 端(B 端) 使用者和用途:企业、H5 作品的作者可以在此产出自己的海报作品,创建、编辑、发布作品 开发方式:前后端分离的方式由 editor-fe + editor-server 组成 平台管理员使用的管理系统(后台) 使用者和用途:平台管理员使用的后台管理系统,可以对作品进行管理,如用户管理,模板管理,作品管理以及数据统计 (统计也会用到第三方,比如百度统计) 开发方式:前后端分离方式,由 admin-fe + admin-server 组成 模块设计 模块拆分和关系图 特殊模块说明 编辑器为独立的组件库,同时用于编辑器和 h5 自研统计服务,因为埋点比较复杂,市面上没有合适的,或者有,但是很贵 数据结构 数据结构思路 尽量符合 vnode 规范 用数组来组织数据,可以保证有序 尽量使用引用关系,不要冗余 数据结构示例 { \"title\": \"\", \"setting\": {}, // 一些可能的配置项,扩展性保证 \"props\": {}, // 页面的一些设置,保证扩展性 \"components\": [ { \"id\": \"xxx\", \"name\": \"文本1\", \"tag\": \"text\", \"attrs\": {}, \"children\": [], }, ], \"activeComponentId\": \"\", } 数据关系流转 扩展性保证 (引导架构设计会的与会人员讨论,集思广益) 扩展能选择的组件,数据结构层面的扩展 扩展编辑器的功能,例如:组件隐藏、锁定 扩展页面的配置,如多语言 开发提效 脚手架:创建、发布 组件平台:减少编写重复代码的时间,对于业务组件进行抽象,积累业务组件 运维保障 线上服务和运维服务 安全 监控和报警 服务扩展性:基于云服务,可以随时扩展机器的配置 发布回滚 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/zy/02-脚手架分析.html":{"url":"pages/zy/02-脚手架分析.html","title":"脚手架分析","keywords":"","body":"02-脚手架分析 关键词 脚手架 Lerna 架构设计 学习方法 架构三部曲:掌握原理 -> 独立思考 -> 总结反思 深度剖析优秀开源项目,由表及里,由浅入深 视角切换:多切换到架构师视角,从全局思考问题 注意事项 整体难度不高,不用担心学不会,坚持打卡写心得 优秀的程序员不止能够实现功能,更能读懂别人的代码,读懂别人的想法 从知名开源项目中汲取养分,为我所用,助我成长 脚手架实现原理 为什么全局安装 @vue/cli 后会添加的命令为 vue ? 因为 @vue/cli 中 package.json 的 bin 字段,指定了安装的命令为 vue。 全局安装 @vue/cli 时,发生了什么? 下载 @vue/cli 这个包到全局的 node_modules。 然后根据 package.json 中的 bin 字段,在全局的 bin 中生成软链接指向 @vue/cli。 执行 vue 命令时发生了什么?为什么 vue 指向一个 js 文件,我们却可以直接通过 vue 命令去执行他? 首先通过环境变量找到 vue.js,然后通过顶部的 #!/usr/bin/env node 指定了环境变量里面的 node 来执行这个 js。 脚手架原理进阶 为什么脚手架是操作系统的客户端? 因为 node 是一个客户端,我们的 js 代码只是一个字符串参数。 如何为自己编写的 node 脚手架创建别名? 创建软连接 ln 命令。 描述脚手架执行的整个过程。 在 $PATH 中查询 vue 命令。相当于执行 which vue。查找实际链接文件。通过 /usr/bin/env node 执行文件。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/":{"url":"pages/郭二蛋/","title":"郭二蛋","keywords":"","body":"郭二蛋 嗨,你好呀!我是郭二蛋,在慕课网混迹已有4个年头,从免费课到实战课到后来的专栏和微课,已经习惯了在慕课网充电学习,期间也认识了不少小伙伴,他们个个都很有才也很骚~ 这门课就当作是在慕课的毕业课程吧,所以要更加认真学习阿,加油!加油!加油! 在这里记录一下学习《web前端架构》课程的笔记和作业。 没有人天生爱学习,可是这个世界只要成绩,与君共勉。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/01-第一周笔记和作业.html":{"url":"pages/郭二蛋/01-第一周笔记和作业.html","title":"第一周笔记和作业","keywords":"","body":"慕课乐高架构方案设计文档 需求(背景) https://www/yuque.com/imooc-lego/zlz87z 范围 三种角色对应三个方面(平台):普通用户使用的 H5(前台)、企业或者说 H5 作者们使用的编辑器(中台)、平台管理员使用的管理系统(后台)。 普通用户使用的 H5 端(C端) 使用者和用途:普通用户,也就是作品的受众,可以对作品进行分享,对业务增长负责。 开发方式:H5 SSR 的方式。 企业/作者们使用的 B 端(B端) 使用者和用途:企业、H5 作品的作者们可以在此产出自己的海报作品,也就是可以创建、发布、编辑作品 开发方式:前后端分离的方式由 editor-fe + editor-server 构成。 平台管理员使用的管理系统(后台) 使用者和用途:慕课乐高这个平台的管理员使用的后台管理系统,可以在此对作品进行管理,如用户管理、模板管理、作品管理以及数据统计(统计这部分也会用到第三方,比如百度统计)。 开发方式:前后端分离的方式由 admin-fe + admin-server 构成。 模块设计 如下图所示(初次接触,画的不好,多多海涵) 核心数据结构 数据结构思路 每个组件尽量符合 vnode 规范 用数组来组织数据,有序 尽量使用引用关系,不要冗余 数据结构示例 { work: { title: '作品标题', setting: {}, // 一些可能的配置项 扩展性保证 props: {}, // 页面的一些设置 扩展性保证 components: [ { id: '1', name: '文本1', tag: 'text', attrs: { fontSize: '20px' }, children: ['文本1'] }, { id: '2', name: '图片1', tag: 'image', attrs: { src: 'xxx.png', width: '120px' }, children: null } ] } } 数据关系流转 一个核心: B端、C端和管理后台都共用一个数据库。 创建作品:初始化一个JSON数据 发布作品:给后端发请求,对JSON数据修改一个标记 保存作品:给后端发请求,保存JSON数据 C端浏览作品: 获取JSON数据,使用SSR渲染页面 屏蔽作品: 给后端发请求,修改一个标记,C端来判断是否显示 扩展性保证 扩展组件 扩展编辑器功能,如锁定、隐藏 扩展页面信息,如增加多语言 扩展其他功能,如大数据计算 研发提效 脚手架:创建、发布 组件平台: 减少编写重复代码的时间,对业务组件进行抽象,积累业务组件 运维保障 线上服务和运维服务 安全 监控和报警 服务扩展性:基于云服务,可以随时扩展机器配置 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/02-第二周笔记和作业.html":{"url":"pages/郭二蛋/02-第二周笔记和作业.html","title":"第二周笔记和作业","keywords":"","body":"脚手架架构设计和框架搭建 站在前端研发的角度,分析开发脚手架的必要性 脚手架核心价值是将研发过程 自动化:项目重复代码拷贝/git操作/发布上线操作 标准化:项目创建/git flow/发布流程/回滚流程 数据化:研发过程数据化、系统化,使得研发过程可量化 自研脚手架和自动化构建工具的区别 市面上已经有了如Jenkins,travis等自动化构建工具,我们为什么还要自研脚手架? 不满足需求:jenkins/travis通常需要在git hooks中触发,在服务端执行,无法覆盖研发人员本地的功能,如创建项目自动化,git操作自动化 定制复杂:jenkins/travis等工具的定制过程需要开发插件,要用到Java语言,对前端开发人员并不友好 从使用的角度来理解什么是脚手架 脚手架简介 其实脚手架的实质就是一个操作系统上的客户端。它通过命令行来执行,下面我们用一个常见的例子来举例: vue create project 上面这条看似简单常见的命令实际上由3个部分组成: 主命令:vue command:create command的param:project 这条命令大家应该都很常见了,它表示创建一个vue项目,项目的名字叫project。 脚手架执行原理 脚手架执行原理如下 在终端输入vue create project 终端解析出vue 在环境变量中找到vue命令 终端根据vue命令链接到实际文件vue.js 终端利用node执行vue.js vue.js解析command或者param vue.js执行command 执行完毕,退出执行 从应用的角度看 如何开发一个脚手架 新建一个文件夹(项目)使用npm进行初始化,打开package.json 配置bin字段,创建一个命令,指向bin/index.js; 将这个项目发布到npm; 全局安装这个脚手架; 使用第一步中bin字段中配置的命令来使用脚手架即可。 脚手架开发流程详解 开发流程 创建项目,使用npm初始化这个项目 创建脚手架入口文件,第一行写如下代码:#!/usr/bin/env node 配置package.json文件,添加bin属性 编写脚手架代码 将脚手架发布到npm 使用流程 安装脚手架:npm install -g imooc-test-erdan 使用脚手架:imooc-test-erdan / imooc-test-erdan -h 把库发布到npm的流程 打开npm的官网,注册一个账号; 打开邮箱,进行验证; npm login 输入账号、密码和邮箱进行登录; npm publish 将项目发布上去。 加深对npm link的使用和理解 新建&连接本地脚手架 mkdir erdan-test cd erdan-test npm init -y mkdir bin cd bin touch index.js npm link 新建本地库文件并在本地脚手架中使用 mkdir erdan-test-lib npm init -y npm link cd erdan-test npm link erdan-test-lib 取消链接本地库文件 cd erdan-test-lib npm unlink cd erdan-test # link存在的情况下执行下面这行 npm unlink erdan-test-lib # link不存在的情况下删除node_modules # 从安装发布到远程仓库上的库文件 npm i -S erdan-test-lib Lerna学习笔记 lerna简介 我们在使用lerna之前,要知道我们为什么要用lerna,我们不妨看看原生开发脚手架存在什么痛点。 重复操作 多package本地link 多package安装依赖 多package代码提交 多package单元测试 多package代码发布 版本一致性 发布时的版本一致性问题 发布后相互依赖版本升级问题 有了上面这些原生开发脚手架的痛点以后,就有了lerna这个优秀的工具。用一句话概述lerna就是一个优化基于git+npm的多package项目的管理工具。 lerna的优势就是可以大幅减少重复操作、提升操作的标准化。 lerna是架构优化的产物,lerna的产生揭示了一个架构真理:项目复杂度提升以后,就需要对项目进行架构优化,架构优化的目的往往都是以效能为核心。 lerna开发脚手架流程图 lerna实操 使用lerna搭建脚手架框架 mkdir tangmen-cli-dev npm init -y npm install -g lerna (// 全局安装) npm install lerna lerna -v ( // 输出版本号说明安装成功) lerna init (// 初始化lerna项目,会创建一个lerna.json) // 经过上面init这一步,会初始化git仓库,再搞一个.gitignore 配置一些不用上传的目录 git remote xxx (// 添加远程仓库) lerna create core (// 创建一个package) lerna create utils(// 又创建了一个package) lerna add (// 批量给两个package都安装依赖) lerna publish (// 发布项目) lerna核心操作 初始化lerna lerna init 创建package lerna create core // 在这一步可以给package起一个别名 为了防止和npm上其它包重名 可以加个前缀@ // 这里要注意的是后面想成功发布这种带前缀的私包的话,需要先在npm上创建一个组织 // 举个栗子:如果你给这个包起的名字叫@tangmen-cli-dev/core // 那你先要建一个叫tangmen-cli-dev的组织 安装依赖 lerna add mocha --dev (// 给所有package都安装) lerna add mocha package/core --dev (给core这个package安装依赖) 清空依赖 lerna clean // 手动从package的package.json中删除依赖 恢复依赖 lerna bootstrap 执行脚本 lerna exec -- rm -rf node_modules (// 在所有package中都执行) lerna exec --scope @tangmen-cli-dev/core --rm -rf node_modules (// 在特定package中执行脚本) 执行 npm script 命令 lerna run test (// 在所有package中都执行) lerna run --scope @tangmen-cli-dev/core test (// 在特定package中执行脚本) 发布项目 lerna publish 学习使用lerna发布项目时候遇到的几个小坑 有没有登录npm tag重复问题 加了@前缀的包默认是private的,要在package.json中改变一下publishConfig 如果发布的是带前缀@的包,一定一定记得要先在npm上穿件一个group package-lock.json不能添加在.gitignore中 作业 已经发布到npm上的简易脚手架 imooc-test-erdan erdan-test-lib @tangmen-cli-dev/core @tangmen-cli-dev/utils 理解Yargs常用API和开发流程 Yargs常用API Yargs.usage(提示脚手架用法) Yargs.strict(开启以后可以报错提示) Yargs.demandCommand(规定最少传几个command) Yargs.recommendCommands(在输入错误command以后可以给你推荐最接近的正确的command) Yargs.alias(起别名) Yargs.options(定义多个option) Yargs.option(定义option) Yargs.fail(错误处理方法) Yargs.group(分组) Yargs.wrap(命令行工具的宽度) Yargs.epilogue(命令行工具底部的提示) Yargs开发流程 脚手架初始化(将process.argv当参数传递给Yargs()) 脚手架命令注册(Yargs.command) 脚手架参数解析(Yargs.parse) 理解lerna实现原理 通过import-local来优先调用本地lerna命令 通过Yargs初始化脚手架,然后注册全局属性,再注册命令,最后通过parse方法解析参数 lerna命令注册时需要传入build和handler两个函数,build用来注册命令专属的options,handler用来处理命令的业务逻辑 lerna通过配置npm本地依赖的方式进行本地开发,具体写法是在package.json中写入:file:your-locale-module-path,在lerna publish的时候会自动替换路径 Node.js模块路径解析流程 Node.js项目模块路径解析是通过require.resolve方法来实现的 require.resolve就是通过Module._resolveFileName来实现的 require.resolve实现原理: Module._resolveFileName核心的3个点: 1.判断是否为内置模块 2.通过Module._resolveLookupPaths生成node_modules可能存在的路径 3.通过Module._findPath查询模块的真实路径 Module._findPath核心流程有4点: 1.查询缓存(将request和paths通过x00合并成cacheKey) 2.遍历paths,将paths与request组成文件路径basePath 3.如果basePath存在则调用fs.realPathSync获取真实路径 4.将真实路径缓存到Module._pathCache(key就是前面生成的cacheKey) fs.realPathSync核心流程有3点: 1.查询缓存(缓存的key为p,也就是上面Module._findPath生成的路径) 2.从左往右遍历路径字符串遇到/时,拆分路径,判断该路径是否为软连接,如果是软连接则查询其真实链接,并生成新路径P,然后继续往后遍历 3.遍历完成得到对应的真实路径,此时会将原始路径original作为key,真实路径保存为value保存到缓存中 require.resolve.paths等价于Module._resolveLoopupPaths,该方法用于获取所有node_modules可能存在的路径 require.resolve.paths的实现原理: 1.如果路径为根目录,直接返回['/node_modules'] 2.否则将路径字符串从后往前遍历,遇见/时,拆分路经,在后面加上node_modules,并传入一个paths数组,直至查询不到/后返回paths数组 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/03-第三周笔记和作业.html":{"url":"pages/郭二蛋/03-第三周笔记和作业.html","title":"第三周笔记和作业","keywords":"","body":"脚手架核心流程开发 脚手架整体架构设计 前端开发过程中的痛点和需求分析 痛点 存在大量重复代码的拷贝 协同开发时,分支混乱, 操作不规范,导致耗时 发布上线耗时,会出现各种各样的错误 需求分析 1.通用的组件/模板创建能力 模板支持定制,定制后能发布生效 模板支持快速接入,极低的接入成本 2.通用的项目/组件发布能力 发布过程中自动完成标准的 git 操作 发布完成后自动删除开发分支并创建 tag 发布后自动完成云构建、cdn、域名绑定 发布过程支持测试/正式两种模式 大厂是如何做项目的 自己动手画了一下示意图 git 操作规范 自己动手画了一下示意图 架构设计图 脚手架模块拆分策略 拆包原则 根据模块的功能来拆分: core: 核心模块 utils: 工具模块 commands: 命令模块 models: 模型模块 拆包结果 核心流程:core 命令模块:commands 初始化 发布 清除缓存 模型: models Command 命令 Project 项目 Component 组件 Npm 模块 Git 仓库 支撑层: utils Git 操作 云构建 工具方法 API 请求 Git API core 模块技术方案 core 模块的技术方案主要分为三个阶段,分别是准备阶段、命令注册、命令执行。第三周的课程内容主要是讲准备阶段。 涉及到的技术点 核心库 import-local commander 工具库 fs-extra (用于文件操作,基于 fs 封装的库) dotenv (可以获取到环境变量) semver (比较 package 的版本) root-check (进行 root 降级) user-home (拿到用户主目录) colors (可以在终端当中打印不同颜色的文本) npmlog (打印日志用,可以进行定制) 实现脚手架准备过程 检查版本号 思路:直接引用 package.json 文件,获取其中的 version 字段,打印到终端。注意:这里打印的时候可以使用 console.log,也可以使用 npmlog 这个依赖库。 const pkg = require('../package.json') function checkVersion() { console.log(pkg.version) // or log.info(pkg.version) } 检查 Node 版本 思路: 获取当前的 node 版本,和我们事先预设好的版本进行比对,如果当前版本较低,那么给用户一个提示。 const semver = require('semver') const colors = require('colors/safe') function checkNodeVersion() { // 获取当前的 node 版本 const currentVersion = process.version // 和我们事先预设好的版本进行比对 const lowestVersion = constant.LOWET_NODE_VERSION // 如果当前版本较低,那么给用户一个提示 if (!semver.gte(currentVersion, lowestVersion)) { throw new Error(colors.red(`tangmen-cli 需要安装${lowestVersion}版本及以上的Node.js`)) } } 检查 root 是否启动 思路:这个功能比较简单,事情都让 root-check 这个库帮我们做了,我们只需要引用并且调用一下就可以实现 root 降级,规避掉因为 root 用户带来的一系列权限问题。 function checkRoot() { const rootCheck = require('root-check') rootCheck() } 检查用户主目录 const userHome = require('user-home') const pathExists = require('path-exists').sync function checkUserHome() { if (!userHome || !pathExists(userHome)) { throw new Error(colors.red('当前用户主目录不存在,请检查!')) } } 检查入参 let args function checkInputArgs() { args = require('minimist')(process.argv.slice(2)) checkArgs() } function checkArgs() { if (args.debug) { process.env.LOG_LEVEL = 'verbose' } else { process.env.LOG_LEVEL = 'info' } log.level = process.env.LOG_LEVEL } 检查环境变量的两种实现方式 function checkEnv() { const dotenv = require('dotenv') const dotenvPath = path.resolve(userHome, '.env') if (pathExists(dotenvPath)) { dotenv.config({ path: dotenvPath }) } createDefaultConfig() log.verbose('环境变量', process.env.CLI_HOME_PATH) } // 创建默认的环境变量配置 function createDefaultConfig() { const cliConfig = { home: userHome } if (process.env.CLI_HOME) { cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME) } else { cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME) } process.env.CLI_HOME_PATH = cliConfig.cliHome } function checkEnv() { const dotenv = require('dotenv') const dotenvPath = path.resolve(userHome, '.env') if (pathExists(dotenvPath)) { config = dotenv.config({ path: dotenvPath }) } config = createDefaultConfig() log.verbose('环境变量', config, process.env.CLI_HOME) } // 创建默认的环境变量配置 function createDefaultConfig() { const cliConfig = { home: userHome } if (process.env.CLI_HOME) { cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME) } else { cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME) } return cliConfig } 检查是否为最新版本 async function checkGlobalUpdate() { // 获取当前用户安装的版本是多少 const currentVersion = pkg.version const npmName = pkg.name // 通过接口请求拿到最新的版本号 const { getNpmSemverVersion } = require('@tangmen-cli-dev/get-npm-info') const latestVersion = await getNpmSemverVersion(currentVersion, npmName) // 拿npm上最新的版本号和本地安装的版本号进行对比,如果前者大于后者,则给用户一个明显的提示 if (latestVersion && semver.gt(latestVersion, currentVersion)) { log.warn( colors.yellow(`请手动更新${npmName}, 当前版本:${currentVersion}, 最新版本: ${latestVersion} 更新命令: npm install -g ${npmName} `) ) } } 本周作业完成情况 绘制脚手架架构设计图(已完成) 实现脚手架准备过程代码(已完成) 通过 commander 实现一个脚手架,包含自定义 option 和 command 功能:npm i -g imooc-test-erdan(已完成) 通过 webpack 和原生两种方式实现 Node 对 ES Module 的支持(已完成) Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/04-第四周笔记和作业.html":{"url":"pages/郭二蛋/04-第四周笔记和作业.html","title":"第四周笔记和作业","keywords":"","body":"脚手架架构优化示意图 脚手架命令动态加载功能架构设计图 本周作业 1.完成tangmen-cli-dev脚手架动态命令执行代码编写 // core/exec/lib/index.js 'use strict'; const cp = require('child_process') const path = require('path') const Package = require('@tangmen-cli-dev/package') const log = require('@tangmen-cli-dev/log') const SETTINGS = { init: '@tangmen-cli-dev/init' } // 缓存目录 const CACHE_DIR = 'dependencies' async function exec() { // 目标目录 let targetPath = process.env.CLI_TARGET_PATH // 用户主目录 const homePath = process.env.CLI_HOME_PATH let storeDir = '' let pkg const cmdObj = arguments[arguments.length - 1] const cmdName = cmdObj.name() const packageName = SETTINGS[cmdName] const packageVersion = 'latest' // 是否执行本地代码 -> 否的话 就执行下面这段逻辑 if (!targetPath) { targetPath = path.resolve(homePath, CACHE_DIR) // 生成缓存路径 // 存储目录 storeDir = path.resolve(targetPath, 'node_modules') log.verbose('targetPath', targetPath) log.verbose('storeDir', storeDir) // 初始化一个Package pkg = new Package({ targetPath, packageName, packageVersion }) // 如果Package存在 if (await pkg.exists()) { // 更新package await pkg.update(); } else { // 安装package await pkg.install(); } } else { pkg = new Package({ targetPath, packageName, packageVersion }) } // 是否执行本地代码 -> 选择是的话 执行下面这段逻辑 // 获取本地代码入口文件 const rootFile = pkg.getRootFilePath(); // 本地代码存在的情况下执行以下逻辑,否则终止执行 if (rootFile) { try { const args = Array.from(arguments); const cmd = args[args.length - 1]; const o = Object.create(null); Object.keys(cmd).forEach(key => { if (cmd.hasOwnProperty(key) && !key.startsWith('_') && key !== 'parent') { o[key] = cmd[key]; } }); args[args.length - 1] = o; // 生成指令执行代码 const code = `require('${rootFile}').call(null, ${JSON.stringify(args)})`; // 启动新进程执行代码 const child = spawn('node', ['-e', code], { cwd: process.cwd(), stdio: 'inherit', }); // 执行产生异常时 打印异常 并终止执行 child.on('error', e => { log.error(e.message); process.exit(1); }); // 执行完毕 正常退出 child.on('exit', e => { log.verbose('命令执行成功:' + e); process.exit(e); }); } catch (e) { log.error(e.message) } } } // windows操作系统spawn执行命令兼容 function spawn(command, args, options) { const win32 = process.platform === 'win32' const cmd = win32 ? 'cmd' : command const cmdArgs = win32 ? ['/c'].concat(command, args) : args return cp.spawn(cmd, cmdArgs, options || {}) } module.exports = exec; // models/package/lib/index.js 'use strict'; const path = require('path') const fse = require('fs-extra') const pkgDir = require('pkg-dir').sync const pathExists = require('path-exists').sync const npminstall = require('npminstall') const {isObject} = require('@tangmen-cli-dev/utils') const formatPath = require('@tangmen-cli-dev/format-path') const {getDefaultRegistry, getNpmLastVersion} = require('@tangmen-cli-dev/get-npm-info') class Package { constructor(options) { // 判断边界情况 如果没有传参 直接提示用户options不得为空 if (!options) { throw new Error('Package类的options参数不能为空') } // 如果参数不是对象的话提示用户options必须是对象 if (!isObject(options)) { throw new Error('Package类的options参数必须是对象') } // package的目标路径 this.targetPath = options.targetPath // 缓存Package的路径 this.storeDir = options.storeDir // package的名字 this.packageName = options.packageName // package的version this.packageVersion = options.packageVersion // package的缓存目录前缀 this.cacheFilePathPrefix = this.packageName.replace('/', '_') } // 准备(预检)阶段 // 如果缓存package的路径目录不存在的话,我们用fs模块创建一个目录 // 如果使用者传进来的版本参数是latest,那么我们就要调取API获取最新版本的信息 async prepare() { if (this.storeDir && !pathExists(this.storeDir)) { fse.mkdirpSync(this.storeDir) } if (this.packageVersion === 'latest') { this.packageVersion = await getNpmLastVersion(this.packageName) } } // 读取缓存路径 get cacheFilePath() { return path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${this.packageVersion}@${this.packageName}`); } // 获取指定的缓存路径 getSpecificCacheFilePath(packageVersion) { return path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${packageVersion}@${this.packageName}`); } // 判断当前的package是否存在 async exists() { if (this.storeDir) { await this.prepare() return pathExists(this.cacheFilePath) } else { return pathExists(this.targetPath) } } // 安装package async install() { await this.prepare() return npminstall({ root: this.targetPath, storeDir: this.storeDir, registry: getDefaultRegistry(), pkgs: [{ name: this.packageName, version: this.packageVersion }] }) } // 更新package async update() { await this.prepare() const latestPackageVersion = await getNpmLastVersion(this.packageName) const latestFilePath = this.getSpecificCacheFilePath(latestPackageVersion) if (!pathExists(latestFilePath)) { await npminstall({ root: this.targetPath, storeDir: this.storeDir, registry: getDefaultRegistry(), pkgs: [{ name: this.packageName, version: latestPackageVersion }] }) this.packageVersion = latestPackageVersion } } // 获取入口文件的路径 async getRootFilePath() { function _getRootFile(targetPath) { // 1.获取package.json所在目录 const dir = pkgDir(targetPath) if (dir) { // 2.读取package.json const pkgFile = require(path.resolve(dir, 'package.json')) // 3.寻找main/lib if (pkgFile && pkgFile.main) { // 路径的兼容 return formatPath(path.resolve(dir, pkgFile.main)) } } return null } if (this.storeDir) { return _getRootFile(this.cacheFilePath) } else { return _getRootFile(this.targetPath) } } } module.exports = Package 'use strict'; const semver = require('semver') const colors = require('colors/safe') const log = require('@tangmen-cli-dev/log') const LOWEST_NODE_VERSION = '12.0.0' class Command { constructor(argv) { if (!argv) { throw new Error('参数不能为空') } if (!Array.isArray(argv)) { throw new Error('参数必须为数组') } if (argv.length { let chain = Promise.resolve() // 检查node版本 chain = chain.then(() => this.checkNodeVersion()); // 初始化参数 chain = chain.then(() => this.initArgs()); // init业务逻辑 chain = chain.then(() => this.init()); // 执行 chain = chain.then(() => this.exec()); chain.catch(err => { log.error(err.message) }) }) } // 初始化参数 initArgs() { this._cmd = this._argv[this._argv.length - 1] this._argv = this._argv.slice(0, this._argv.length - 1) } // 检查node版本 checkNodeVersion() { const currentVersion = process.version const lowestVersion = LOWEST_NODE_VERSION if (!semver.gte(currentVersion, lowestVersion)) { throw new Error(colors.red(`tangmen-cli 需要安装${lowestVersion}版本及以上的Node.js`)) } } // 交给子类去实现 init() { throw new Error('init必须实现!'); } // 交给子类去实现 exec() { throw new Error('exec必须实现!'); } } module.exports = Command Node多进程源码总结 exec和execFile/fork/spawn的区别? exec: 原理是调用/bin/sh -c执行我们传入的shell脚本,底层调用了execFile execFile: 原理是执行我们传入的file和args,底层调用了spawn创建和执行子进程,并建立了回调,一次性将所有的stdout和stderr结果返回 spawn: 原理是调用了internal/childprocess,实例化了ChildProcess子进程对象,再调用child.spawn创建子进程并执行命令,底层是调用了child. handle.spawn执行process_wrap中的spawn方法,执行过程是异步的,执行完毕后通过PIPE进行单向数据通信,通信结束后子进程会发起onexit回调,同时Socket会执行close回调 fork: 原理是通过spawn创建和执行子进程命令,采用node执行命令,通过setupchannel创建IPC用于子进程和父进程之间的双向通信 data/error/exit/close回调的区别 data: 主进程读取数据过程中通过onStreamRead发起的回调 error: 命令执行失败后发起的回调 exit: 子进程关闭完成后发起的回调 close: 子进程所有Socket通信端口全部关闭后发起的回调 stdout close/stderr close: 特定的PIPE读取完成后调用onReadableStreamEnd关闭Socket时发起的回调 Node多进程执行阶段总结 补充:在自己电脑上如何配置多个公钥 因为疫情的原因,国际庄现在不让出门,我平时是用公司的电脑进行练习的,这次用自己的电脑来配置公钥,但是遇到一个问题:我们这个仓库是在github的,但是我另一个仓库是在gitee上面存放的,于是我使用现有的账号可以正常拉取、推送到github,但是推送到gitee的时候它告诉我说权限不足。 通过百度得知是有办法解决的,那就是在一台电脑上配置多个ssh-key,经过参考网上的教程,终于调通了,将这次经历记下来,如果你和我有一样的问题,希望能帮到你。 这里偷个懒,将教程的链接直接贴在这里了:https://www.cnblogs.com/popfisher/p/5731232.html 石家庄加油!河北加油! Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/郭二蛋/05-第五周笔记和作业.html":{"url":"pages/郭二蛋/05-第五周笔记和作业.html","title":"第五周笔记和作业","keywords":"","body":"脚手架创建项目流程设计和开发 脚手架项目创建功能架构设计 “凡事预则立,不预则废”。在开始本周的编码工作之前呢,sam 老师一如既往的会给我们讲一下本周我们要做的内容是什么以及架构设计和流程是怎样的,具体来说主要包括了项目创建前准备阶段架构设计和下载项目模板阶段架构设计两个部分。 项目创建前准备阶段架构设计 下载项目模板阶段架构设计 项目基本信息获取功能开发 根据上面我们画的架构设计图来看,在准备阶段我们要做的事情还真不少呢,概括的说就是获取基本信息,而这些信息从哪里来呢?自然是要让使用者告诉我们啦,那这里就有一个非常好用而强大的库帮助我们和使用者交互,它就是 inquirer。在这一小章节中,我们要完成的功能主要有以下几项: 判断当前目录(要运行我们的脚手架命令进行模板安装的那个目录)是否为空 inquirer 的基本用法和常用属性入门、多种交互形式的演示 强制清空当前目录功能开发 获取项目基本信息功能开发 项目名称和版本号的合法性校验 判断当前目录(要运行我们的脚手架命令进行模板安装的那个目录)是否为空 我们这里使用的是 Node.js 提供给我们的文件系统操作模块(fs)。 isDirEmpty(localPath) { let fileList = fs.readdirSync(localPath) // 文件过滤的逻辑 fileList = fileList.filter(file => (!file.startsWith('.') && ['node_modules'].indexOf(file) 强制清空当前目录功能开发 我们要先判断当前目录是否为空,在不为空的情况下我们会使用 inquirer 来询问用户是否要继续创建项目,这里要注意的是 force 参数的获取;但是因为清空文件夹的操作是一个不可逆的操作,我们还是要至少询问一次用户是否确认清空。如果用户确认清空,那我们就会清空当前目录,用到的库是 fs-extra。 const localPath = process.cwd() if (!this.isDirEmpty(localPath)) { // 询问是否继续创建 使用到inquirer这个库 // 如果 用户不是强制更新,那么就要询问用户是否继续创建 let ifContinue = false if (!this.force) { ifContinue = ( await inquirer.prompt({ type: 'confirm', name: 'ifContinue', message: '当前目录不为空,是否继续创建?', default: false }) ).ifContinue if (!ifContinue) { return } } // 不管用户是否是强制更新,最后都会展示这次询问,因为清空当前目录文件是一个非常严谨的操作 if (ifContinue || this.force) { // 做二次确认 const { confirmDelete } = await inquirer.prompt({ type: 'confirm', name: 'confirmDelete', message: '是否确认清空当前目录下的文件?', default: false }) if (confirmDelete) { // 清空当前目录 使用 fse-extra fse.emptyDirSync(localPath) } } } 获取项目基本信息功能的开发 在清空了文件夹以后,我们要询问用户一些基本信息,比如这个项目的名字、版本号以及可能存在的描述信息(组件模板的情况下),将来这些信息都会通过 ejs 模板引擎渲染到 package.json 文件中。 // 声明一个对象用来接收项目信息 最后返回的也是这个对象 let projectInfo = {} // 校验项目名称的正则,封装在一个函数内 function isValidName(v) { return /^[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(v) } // 默认项目名称是不通过的 let isProjectNameValid = false // 如果用户在输入命令时的名称符合我们的规则 就直接用这个 if (isValidName(this.projectName)) { isProjectNameValid = true projectInfo.projectName = this.projectName } // inquirer获取用户想要下载的是组件模板还是项目模板 const { type } = await inquirer.prompt({ type: 'list', name: 'type', message: '请选择初始化项目类型?', default: TYPE_PROJECT, choices: [ { name: '项目', value: TYPE_PROJECT }, { name: '组件', value: TYPE_COMPONENT } ] }) // 通过条件过滤对应的模板 this.template = this.template.filter((template) => { return template.tag.includes(type) }) const title = type === TYPE_PROJECT ? '项目' : '组件' // 兼容项目和模板两种情况的交互询问 const projectNamePrompt = { type: 'input', name: 'projectName', message: `请输入${title}名称`, default: '', validate: function (v) { const done = this.async() // 1.首字符必须为英文字符 // 2.尾字符必须为英文字符或数字,不能为字符 // 3.字符仅允许“-_” // 4.兼容只有一个字母的情况 setTimeout(function () { if (!isValidName(v)) { done(`请输入合法的${title}名称,例:a1 | a_b_c | a1_b1_c1`) return } // Pass the return value in the done callback done(null, true) }, 0) }, filter: function (v) { return v } } // 这个数组是最后要传给inquirer的参数 const projectPrompt = [] // 如果用户在命令行输入的名称不符合我们的要求,那么我们就将后来用户输入的名称添加到我们的数组中 if (!isProjectNameValid) { projectPrompt.push(projectNamePrompt) } // 除了项目名称以外 我们还要知道用户输入的版本号、选择的模板 projectPrompt.push( { type: 'input', name: 'projectVersion', message: `请输入${title}版本号`, default: '1.0.0', validate: function (v) { const done = this.async() setTimeout(function () { if (!!!semver.valid(v)) { done('请输入合法的项目版本号,例:1.0.0') return } // Pass the return value in the done callback done(null, true) }, 0) return }, filter: function (v) { if (!!semver.valid(v)) { return semver.valid(v) } return v } }, { type: 'list', name: 'projectTemplate', message: `请选择${title}模板`, choices: this.createProjectTemplate() } ) // 如果用户选择的是项目模板 那我们直接将上面的projectPrompt传递给inquirer即可 然后用将所有我们要用到的信息进行拼装,就是我们要的projectInfo if (type === TYPE_PROJECT) { const project = await inquirer.prompt(projectPrompt) projectInfo = { ...projectInfo, type, ...project } } else if (type === TYPE_COMPONENT) { // 如果用户选择的是组件模板,那么我们要在前面的基础上追问一条描述信息 const descriptionPrompt = { type: 'input', name: 'componentDescription', message: '请输入组件描述信息', default: '', validate: function (v) { const done = this.async() setTimeout(() => { if (!v) { done('请输入组件描述信息') return } done(null, true) }, 0) } } projectPrompt.push(descriptionPrompt) const component = await inquirer.prompt(projectPrompt) projectInfo = { ...projectInfo, type, ...component } } // 最后我们对拿到的项目信息进行一些转换 这里在转换项目名称的时候用到了kebab-case这个库,可以帮助我们将驼峰格式的名称转为连字符格式的 // 生成classname if (projectInfo.projectName) { projectInfo.name = projectInfo.projectName projectInfo.className = require('kebab-case')(projectInfo.projectName) } // 生成version if (projectInfo.projectVersion) { projectInfo.version = projectInfo.projectVersion } // 生成description if (projectInfo.componentDescription) { projectInfo.description = projectInfo.componentDescription } // 至此,我们想要的项目基本信息就获取完成了 return projectInfo egg.js + 云 mongodb 快速入门 在看这部分的时候没有感到什么阻力,可能之前学了双越老师、7 七月老师的相关课程吧,做 web server 的时候用了 mongodb 和 mysql 两种数据库,也就没有开通云 mongodb,所使用的是我们自己服务器上安装的 mongodb 数据库,新建了一个数据库;将 egg.js 模板的代码进行一番修改以后就达到了我们课程的效果(改成自己的接口地址,返回我们自己数据库的内容);最后将服务运行在自己的服务器上面,使用 nginx 进行 7001 端口的转发。 项目模板开发 + 获取项目模板 API 开发 这里的话我上传了一个 vue3 的模板(使用 vue-cli 创建的项目进行了删减)和花裤衩大佬的 vue-element-admin 模板总共两个模板进行测试,对接的是自己服务器的接口,内容比较简单,就不进行记录了。 脚手架项目模板下载功能开发 到了这一步,我们在前面创建的 Package 这个类就派上用场了,会发现我们已经将安装和更新功能都封装好了,直接用就好了,很方便~,如果模板不存在的话,就调用 Package 实例的 install 方法进行安装,如果存在的话,就要调用 Package 实例的 update 方法进行更新。 async downloadTemplate() { const { projectTemplate } = this.projectInfo const templateInfo = this.template.find((item) => item.npmName === projectTemplate) const targetPath = path.resolve(userHome, '.tangmen-cli-dev', 'template') const storeDir = path.resolve(userHome, '.tangmen-cli-dev', 'template', 'node_modules') const { npmName, version } = templateInfo this.templateInfo = templateInfo const templateNpm = new Package({ targetPath, storeDir, packageName: npmName, packageVersion: version }) if (!await templateNpm.exists()) { const spinner = spinnerStart('正在下载模板...') await sleep() try { await templateNpm.install() } catch (e) { throw e } finally { spinner.stop(true) if (await templateNpm.exists()) { log.success('下载模板成功') } this.templateNpm = templateNpm } } else { const spinner = spinnerStart('正在更新模板...') await sleep() try { await templateNpm.update() } catch (e) { throw e } finally { spinner.stop(true) if (await templateNpm.exists()) { log.success('更新模板成功') } this.templateNpm = templateNpm } } } inquirer源码解析 暂时没啃这块,待更新~ Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🎮滔/":{"url":"pages/🎮滔/","title":"🎮滔","keywords":"","body":"滔 - 🎓 学习分享 🎓 🤝 多多指教 🤝 第一周:01-需求分析及架构设计 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🎮滔/01-需求分析及架构设计.html":{"url":"pages/🎮滔/01-需求分析及架构设计.html","title":"需求分析及架构设计","keywords":"","body":"整体架构设计 v1.0 1. 需求 需求文档 2. 模块设计 项目主要分为三个大端: 编辑器端 H5作品展示端 管理端 除H5端外,均采用前后端分离模式进行开发。此外,为提H5作品展示端的渲染性能,采用服务端渲染。 模块受众: 编辑器端:设计师及其他用户 H5端:作品受众、普通用户 管理端:网站管理人员 模块职责简述: 编辑器端制作发布作品、保存模板,并能查看作品的浏览、分享等数据,管理账户作品及模板等 H5端用于显示成品作品,使用服务端渲染提高性能与用户体验,收集浏览及分享数据,发送到统计服务端 管理端管理作品,紧急下架,编辑器端用户管理,查看网站所有数据(用户数、浏览量、作品数量等) 其他重要部分: 所有数据共用一个数据库 开发一个属于该项目的脚手架,提高开发效率 自研自定义事件统计服务,让项目闭环使日后有方向地让业务增长 开发一个属于本项目的组件库,提高开发效率,为了创作作品后的效果和H5端显示的效果一致,编辑器端及H5作品展示端都使用该组件库 示意图: 3. 数据结构 数据应使用vnode结构 组件内容使用 数组-对象 结构(有序,引用) [ { id: 1, name: \"title\", ... }, { id: 2, name: \"detail\", ... } ] vux store数据结构 { work: { title: \"\", setting: { // 预留页面设置 }, props: { // body配置 }, components: [ { id: 1, name: \"title\", tag: \"text\", attrs: { // 属性 }, content: \"标签里的内容\", children: [ // 子元素 ], }, { id: 2, name: \"detail\", ... }, ... ], activeComponentsId: \"1\", // 当前选中组件 } } 通过计算属性计算出当前选中的组件,vux getter: { layers() => { store.work.components.map(c => { return { id: c.id, name: c.name } }) } } 4. 数据扭转 简述: 项目共用一个数据库 编辑器端及管理端前后端分离 作品发布默认作品状态正常(state: 1),下架作品状态设为 0 (state: 0) 创建作品时,初始化一个默认的作品vnode数据 { work: { title: \"\", setting: { }, props: { }, components: [], activeComponentsId: \"\", } } 5. 扩展 扩展组件 锁定、隐藏组件 页面配置 6. 开发提效 组件平台 脚手架 7. 运维保障 显示服务 运维服务 项目安全 监控及报警 流量大时扩展 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🐏羊羽/":{"url":"pages/🐏羊羽/","title":"🐏羊羽","keywords":"","body":"学习分享 技术方案设计文档 课程相关学习资料 GitHub 的 Fork 是什么 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🐏羊羽/01-技术方案设计文档.html":{"url":"pages/🐏羊羽/01-技术方案设计文档.html","title":"技术方案设计文档","keywords":"","body":"技术方案设计文档 问题 项目是用来做什么的? 项目是什么样的架构? 需求背景 https://www.yuque.com/imooc-lego/zlz87z 项目描述 功能主要分为三个部分:运营管理服务、移动端用户服务、系统管理服务; 运营管理服务 给用户提供作品创建、发布、删除作品、恢复作品、统计等服务; 移动端用户服务 用来给用户展示发布的作品,收集用户的访问信息到统计服务; 系统管理服务 管理用户作品的发布,对用户的各种行为进行统计 总结 想要成为一名架构师对于项目应该有完整、闭环、全面这个三个方面的思考。完整和全面是要对项目要有全面的思考,要站在业务全局的角度上面思考问题,闭环是项目要有输入输出,最终形成一个闭环。作品管理、用户查看、采集数据、作品管理查看数据形成一个业务完闭环,系统管理、对作品的管理、数据收集、系统管理检测数据也形成一个闭环。 模块设计 系统应该分为三个主要的业务模块、一个服务收集模块、前端组件模块、脚手架模块; 业务模块应该分别完成:作品创建及作品相关的管理(作品添加、删除、修改、查看、统计)、实现作品价值的模块(使用移动端界面、可以收集用户的数据)、对平台上所有的作品进行管理的模块(屏蔽一些作品、查看作品的一些统计)。 数据采集模块按照业务需要对数据库种的数据进行统计、汇总。 前端组件模块可以被业务模块的前端调用; 脚手架模块简化项目编码、测试、发布、运维的流程 核心数据结构设计 画布的数据模块应该使用JSON来进行保存,可以使用redux、vuex之类的状态管理工具来动态实时的更新、响应数据。 { 'name': '画布名称', // 画布的名称、创建时间、修改者等画布的属性数据 // .... 'content': [ // 画布中的内容 { // 标签名称、文案、唯一的key、样式 }, // 各种画布中的组件 // ... ], 'selected': 'key', // 被选中的key,用来决定浮层谁被选中 } 拓展性保证 前端组件的可拓展性 后端接口的可拓展性 研发提效 组件化开发 脚手架开发 运维保障 拥有具备运维技能的专业工程师 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🐟红鲤驴与绿驴鱼/":{"url":"pages/🐟红鲤驴与绿驴鱼/","title":"🐟红鲤驴与绿驴鱼","keywords":"","body":"红鲤驴与绿驴鱼 - 学习分享 第一周笔记 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/🐟红鲤驴与绿驴鱼/01-作业-架构方案设计.html":{"url":"pages/🐟红鲤驴与绿驴鱼/01-作业-架构方案设计.html","title":"作业 架构方案设计","keywords":"","body":"整体架构设计方案 v1.0 需求 需求地址 范围 整体设计,架构设计,没有细节 编辑b端(前后分离)、项目服务端(中台)、管理端(前后分离)、作品展示c端(服务端渲染) 模块设计 模块的拆分和关系图,结果模块的关键功能,职责等特殊的模块重点说明 组件库,独立第三方,同时用于编辑器和 H5 自研统计服务,为何自研 作品的数据结构 vuex store 的结构,解释数据流转关系图 { // 作品 work: { title: '作品标题', setting: { /* 一些可能的配置项,用不到就先预留 */ }, props: { /* 页面 body 的一些设置,如背景色 */ }, components: [ // components 要用数组,有序结构 // 单个 node 要符合常见的 vnode 格式 { id: 'xxx', // 每个组件都有 id ,不重复 name: '文本1', tag: 'text', attrs: { fontSize: '20px' }, children: [ '文本1' // 文本内容,有时候放在 children ,有时候放在 attrs 或者 props ,没有标准,看实际情况来确定 ] }, { id: 'yyy', name: '图片1', tag: 'image', attrs: { src: 'xxx.png', width: '100px' }, children: null }, ] }, // 画布当前选中的组件 activeComponentId: 'xxx' } vuex getter 选择当前选中的图层 { layers() => { store.work.components.map(c => { return { id: c.id, name: c.name } }) } } 扩展性保证 扩展组件,数据结构层面扩展编辑器的功能,例如:组件隐藏、锁定扩展页面的配置(讨论,集思广益) 开发提效 脚手架 创建:可以开发快速创建项目原型的脚手架,来省去配置项目初始化的时间。 脚手架 发布:。。。 组件平台 运维保障 线上服务和运维服务安全监控和报警服务扩展性:流量大 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🎓风情炀/":{"url":"pages/👨🎓风情炀/","title":"👨🎓风情炀","keywords":"","body":"👨🎓风情炀 - 作业 先入坑打卡,后面补充 目录 01-weak01学习笔记 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🎓风情炀/01-weak01学习笔记.html":{"url":"pages/👨🎓风情炀/01-weak01学习笔记.html","title":"Weak01学习笔记","keywords":"","body":"慕课乐高架构方案设计文档 有空再补充 需求背景 范围 模块设计 数据结构 扩展性保证 研发提效 运维保障 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫Sam老师/01-前端未来趋势分析.html":{"url":"pages/👨🏫Sam老师/01-前端未来趋势分析.html","title":"前端未来趋势分析","keywords":"","body":"前端未来趋势分析 前端未来趋势是一个非常大的命题,它错综复杂,涉猎广泛,今天我试图从前端工程师的视角来分析行业未来的发展趋势,这与我们每个前端工程师都息息相关。 趋势一:融合 基本判断:前端与其他领域结合更加紧密,前端领域分工将更加精细 在技术融合的趋势下,前端将不断与其他领域进行融合,开发出各种令人惊叹的应用: 前端+算法:算法将大大提升前端效能,大家可以参考imgcook,这是一个由淘宝团队推出的根据设计稿自动生成前端代码的工具,相信在不远的未来根据设计稿直接生成业务代码不是梦! 前端+后端:在Node.js+express/koa2/egg.js等一系列后端框架的驱动下,前端和后端结合越来越紧密,从最早的前后端分离,到Serverless、GraphGL,在可预见的未来,前端工程师将包揽所有业务逻辑,并且通过Serverless技术快速生产API,独立完成整个业务系统的研发、发布和运维,所以一手流利的服务端代码能力是必备技能。 前端+架构:前端架构师是未来发展的主流趋势,每个具有一定规模的前端团队都需要合格的前端架构师,前端架构师将完成团队基础架构和工具链设计和开发,并为团队或公司设计和规划业务架构,为公司创造海量业务价值。 趋势二:中台 基本判断:前端中台系统将迅速崛起和壮大 前端工程化的快速普及催生了前端中台的快速发展,一线互联网大厂前端中台发展速度极快,不管是面向营销的h5搭建系统,还是Native动态定制,又或是复杂的中后台可视化搭建平台,可谓百花齐放、应有尽有,前端中台已然成为前端发展的重要方向之一,未来将有大量前端工程师专门从事中台开发,中台开发的核心是前端架构师,他需要负责复杂的中台系统架构、研发效能监控和提升,这是一个极具挑战的工作,但大势所趋,中台的时代已经到来。 趋势三:跨端 基本判断:跨端技术的迅速发展催生新型研发模式 曾几何时,App和Web是完全不同的两个领域,但h5、小程序的火爆,加上javascript日趋成熟,各种跨端技术如雨后春笋,从构建时到运行时,跨端技术正大踏步地前行,面对跨端技术,前端工程师必须拥抱。而跨端技术的背后是高水准前端架构师的精巧构思,掌握跨端技术,合理选择技术栈,是前端工程师的必修课。 总结 要跟紧时代,与时俱进,那么就一定要保持开放的思维,不断吸收新的知识,不断迭代旧的思想,不断拓宽能力边界。前端的发展势头汹涌而又壮阔,每一名前端工程师都有可能成为弄潮儿,这是前端的黄金时代,也是我们每一名前端工程师的黄金时代。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫Sam老师/02-为什么要学习前端架构.html":{"url":"pages/👨🏫Sam老师/02-为什么要学习前端架构.html","title":"为什么要学习前端架构","keywords":"","body":"为什么要学习前端架构 无处不在 首先架构无处不在,架构的本质是解决业务快速增长中的技术复杂度问题,所以只要你所在的组织业务存在增长,就需要用架构的思想去解决一些问题,比如: 项目代码量越来越大,如何提升项目的构建性能? 如何抽取项目公共模块进行快速复用? 如果你没有架构思维和相对应的技术能力,面对这些问题的时候是无从下手的。所以学习架构的第一目标是为了应对和解决项目开发中碰到的各类问题,通常需要架构层面去解决的问题包括: 工程问题 复杂业务 复用问题 至关重要 其次架构至关重要,2009年node诞生以后,前端工程化得到飞速发展,前端项目量级和研发效率直线上升,目前前端领域已出现进一步细分的趋势,主要有三个方向: 前端业务开发 前端全栈开发(偏服务端node) 前端基础架构开发(偏工具) 而前端架构师可能是这三个岗位中的任意一个: 偏业务的前端架构师主要解决复杂业务问题 偏服务端的前端架构师主要解决服务架构和运维体系问题 偏基础架构的前端架构师主要解决研发体系和效能的问题 所以不管你当前处于哪个岗位、哪个阶段,前端架构对你而言都有价值、都非常重要。 直通高薪 最后架构直通高薪,通过调研不难发现很多中级以上的前端开发岗位中已经对架构能力有需求,包括组件库研发、性能优化、工具开发等等,而高级前端职位中,前端架构能力几乎是绝对和必须的,随着前端技术的飞速发展,薪资基于已经与服务端旗鼓相当,所以掌握架构能力毫无疑问是快速进阶高薪的法宝。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫Sam老师/03-脚手架入门.html":{"url":"pages/👨🏫Sam老师/03-脚手架入门.html","title":"脚手架入门","keywords":"","body":"脚手架入门 脚手架简介 脚手架本质是一个操作系统的客户端,它通过命令行执行,比如: vue create vue-test-app 上面这条命令由 3 个部分组成: 主命令: vue command: create command 的 param: vue-test-app 它表示创建一个 vue 项目,项目的名称为 vue-test-app,以上是最一个较为简单的脚手架命令,但实际场景往往更加复杂,比如: 当前目录已经有文件了,我们需要覆盖当前目录下的文件,强制进行安装 vue 项目,此时我们就可以输入: vue create vue-test-app --force 这里的 --force 叫做 option,用来辅助脚手架确认在特定场景下用户的选择(可以理解为配置)。还有一种场景: 通过 vue create 创建项目时,会自动执行 npm install 帮用户安装依赖,如果我们希望使用淘宝源来安装,可以输入命令: vue create vue-test-app --force -r https://registry.npm.taobao.org 这里的 -r 也叫做 option,它与 --force 不同的是它使用 -,并且使用简写,这里的 -r 也可以替换成 --registry,有的同学可能要问,为什么老师知道这个命令,其实我们输入下面的命令就可以看到 vue create 支持的所有 options: vue create --help -r https://registry.npm.taobao.org 后面的 https://registry.npm.taobao.org 成为 option 的 param,其实 --force 可以理解为:--force true,简写为:--force 或 -f 脚手架的执行原理 脚手架的执行原理如下: 在终端输入 vue create vue-test-app 终端解析出 vue 命令 终端在环境变量中找到 vue 命令 终端根据 vue 命令链接到实际文件 vue.js 终端利用 node 执行 vue.js vue.js 解析 command / options vue.js 执行 command 执行完毕,退出执行 从应用的角度看如何开发一个脚手架 这里以 vue-cli 为例 开发 npm 项目,该项目中应包含一个 bin/vue.js 文件,并将这个项目发布到 npm 将 npm 项目安装到 node 的 lib/node_modules 在 node 的 bin 目录下配置 vue 软链接指向 lib/node_modules/@vue/cli/bin/vue.js 这样我们在执行 vue 命令的时候就可以找到 vue.js 进行执行 还有很多疑问需要解答 为什么全局安装 @vue/cli 后会添加的命令为 vue? npm install -g @vue/cli 全局安装 @vue/cli 时发生了什么? 为什么 vue 指向一个 js 文件,我们却可以直接通过 vue 命令直接去执行它? Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫双越老师/":{"url":"pages/👨🏫双越老师/","title":"👨🏫双越老师","keywords":"","body":"双越老师 - 课程分享 请直接看下级目录 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫双越老师/01-我如何理解Web前端架构师的角色和职责.html":{"url":"pages/👨🏫双越老师/01-我如何理解Web前端架构师的角色和职责.html","title":"我如何理解Web前端架构师的角色和职责","keywords":"","body":"我如何理解 Web 前端架构师 的角色和职责 架构师的核心指责:保证业务增长 —— 《聊聊架构》 架构师这个角色,在行业中和各个公司中,都没有明确的定位。甚至,有些公司都没有架构师这个职位。 但是,你的身边总是需要这样的角色。他们技术能力好,有深度、有广度,熟悉公司产品的业务需求,熟悉公司各个部门和负责人,遇到问题能拆分任务,计划和跟踪 …… 即,他们不仅仅是做开发,还有其他更加重要的工作。有了这个角色,你就有了依靠,你就会感觉很踏实,很放心。这种角色,就是架构师。 特别是近些年技术栈细分严重,大家各司其职,更加需要这样的角色去整合团队的工作。保证多人协作顺利有效的进行,否则就乱套了。 无论是大公司还是创业公司,只要有了研发团队,不是单兵作战或者小作坊(通讯靠吼),就需要这样的角色。 下面,我根据我的工作经验和理解,说一下 Web 前端架构师这个角色的一些职责。虽然没法给出一个文字定义,但可以从不同的方面来表达一下。 负责人 首先,作为 Web 前端架构师,你就是前端及相关技术方面的负责人。只要跟你相关的,你都要负责,赢了给你奖励,输了你也要得到惩罚。 所以,架构师就是“将”。所谓“千军易得一将难求”,招聘人员很简单,但招聘一个架构师是很难的。一般情况,都是从本公司培养。 三国时 “蜀国无大将廖化作先锋”,蜀国此时也不是没人了,只是没将了。 这个项目或者系统,交给一个架构师(再配一些开发人员)老板就会安心,一切都在掌控之中,不会发生惊喜,但也不会有意外。 高效 有节奏 稳定 安全 高效:发挥每个人的最大价值,不让人闲着。但这并不代表要加班,要 996 —— 反而加班 996 就是因为没有高效而导致的。 有节奏:当下有安排,未来有计划,做完一个任务立马安排下一个任务,持续进行中。 稳定:完善的研发流程(单元测试,接口测试),完善的监控报警体系,才能保证稳定,课程中都会讲到。 安全:不会被轻易攻击,如最常见的 DDOS XSS SQL 注入等。 PS:如何做到以上几点,以及如何让老板放心,这都是有方法论的。具体哪些方法,大家可以参考我们的课程。 深入理解业务 脱离业务的架构,就是耍流氓,架构是基于业务的 —— 要再说:不想做业务,想做架构。 架构师的核心职责是保证业务增长,翻译过来就是:如何用技术只支撑现在和未来的业务。所以,你得非常清楚的了解公司产品的业务,未来规划和目标。 所以,建议各位同学,如果现在的工作机会还不错,一定要积极参与到公司产品业务的讨论中,不要只是一门心思的写代码。 技术是为业务服务的,光靠技术,没有持久的竞争力。 个人技术能力 架构师也要写代码,且要有广度和深度。 广度:做技术方案时,要有多种选择,且能熟悉前后端的关系。 深度:要能解决一些别人搞不定的问题,不一定是亲自解决,可以指导从某个方向入手查询。 总结 无论公司有没有架构师的职位,无论你现在是否还在一线开发。 只要是作为开发人员,你都要学会以架构师的思维去思考问题,这样才能保证持久竞争力。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫双越老师/02-Web 前端架构师课 vs 普通实战课.html":{"url":"pages/👨🏫双越老师/02-Web 前端架构师课 vs 普通实战课.html","title":"Web 前端架构师课 Vs 普通实战课","keywords":"","body":"Web 前端架构师课 vs 普通实战课 我们要做一门不一样的课,要能体现出“架构师”这个主题,要和普通的实战课做出明显的区别。 在课程制作过程中,我们三位讲师经常自我提问:我们这门课和实战课有何区别呢?—— 我们必须要说服自己,否则就自欺欺人了。 最终,我们总结出了以下几点,证明我们这门课和实战课确实完全不一样。 真正的线上项目,不是 demo 有一次和七月老师打电话,我们聊了一个多小时,我们都承认,现在的实战课,都是 demo ,远远达不到生产环境的级别要求。 线上项目和 demo 虽然功能看似一样,但实则完全不同。随随便便就能说出很多方面: demo 没有线上环境,如域名,服务器,数据库等 demo 没有上线、回滚的流程 demo 没有运维监控和报警,这些在实际工作中都是重点 demo 没有统计、分享等正式的业务场景 demo 不用考虑安全、攻击、敏感内容过滤等 demo 不用担心万一半夜出 bug 该怎么办? …… 还有很多,一次性说不完,都在课程里 【注意】并不是说课程中讲到了上述知识点,它就是线上项目了。光讲知识点没用,必须得把项目正式上线,用正式的域名、证书、服务器等跑起来,而且要流程闭环才可以。 业务负责度高,流程闭环 脱离了业务谈架构,就是耍流氓。做架构师课,就得用复杂度高的业务,否则体现不出来。 h5 编辑器,是前端领域中一个非常复杂的业务,这跟“社区” “电商”这种实战课项目,不是一个难度级别。 全栈,流程闭环:创建 h5 ,发布,分享,还有统计,这是闭环的,实战课里是没有这样做的。实战课讲的,都是完整流程的一个环节而已。 不讲业务代码,不讲基础知识 业务代码会演示,但不会在一行一行带着写了。基础知识也不再详细讲,如 vue3 ts 语法等。 实战课基本都 20h 左右,而且要详细演示代码,根本做不出来这么复杂的项目。 我看过其他的号称架构师的课,虽然时间很长,但是大部分都用在讲基础知识上,做的项目也远远达不到这个复杂度。 有些课程会讲框架源码、造轮子,这看似很牛 x ,但其实这些仅仅是架构师的一个能力“个人技术深度”,对于架构师整体的技能,这是很小的一个方面,算不了什么。 更关注设计、研发流程、运维 这些远比开发重要,特别是运维。 如何开发,大部分业务代码,大家学实战课就好了,这些没多少难度。 而设计、流程和运维,这些是实战课不常见的,也是架构师最需要了解的内容 —— 否则,大家都会开发,凭什么你是架构师呢? 总结 实战课能带你从 0 到 1 入门,接下来 1 - 2 就需要架构师课来帮助你突破瓶颈。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫双越老师/03-动真格的了!为做一门课程花费 1.5万 购买云服务.html":{"url":"pages/👨🏫双越老师/03-动真格的了!为做一门课程花费 1.5万 购买云服务.html","title":"动真格的了!为做一门课程花费 1.5万 购买云服务","keywords":"","body":"动真格的了!为做一门课程花费 1.5万 购买云服务.md 最贵的 iPhone12 Pro Max 要 11899 元,我没有买。今年新出的 iPad mini 据说玩游戏体验很好,要 2921 元,我也没有买。 我把这些钱都花在了正在制作的课程上,1.5w 购买了各种云服务:两台云服务器、各种数据库、OSS、CDN、域名、https 证书、Web 防火墙、短信服务、内容审核服务…… 哦,还花钱请了以为 UI 设计师来设计页面。 你可能会疑问:就讲一门课而已吗,还需要花钱?现在网上各种“Vue 做电商”,就写代码就好了,一分钱都不用花。 对此,我也有一个疑问:现在有哪一门课程,讲师会亲自花钱来投资?(平台的广告、运营费用不能算哈~) 你可以说我:不按套路出牌,可能会踩坑~ 但我还是要坚持自己的风格和态度:输出优质内容,独立思考,做不一样的事情,做真正有价值的课程! PS:课程链接这里不写了,有意向的可以私聊我。本文我们只谈钱~ 为何要花钱呢? 书归正传。不开玩笑、不卖关子了,正式解释一下这个问题。 其实答案很简单 —— 我要做一个真实的线上项目,而不是 demo 。这是项目地址 https://www.imooc-lego.com/ ,有兴趣的可以体验,这里不过多介绍。【但是】要解释一下,虽然看着就是一个网站,但它背后有 12 个代码仓库,所以复杂度还是很高的。 我要把一个真实项目的从 0 到 1 的过程,搬到课程里。包括需求、架构设计、技术方案、研发流程、CI/CD ,发布上线/回滚,运维,监控和报警。 我在这最近忙碌的半年多里,我都傻傻分不清自己到底是一名讲师,还是一名外包。 讲课为何非得用真实项目,不都是 demo 吗? 这个问题要分开说。 入门适合用 demo 零基础入门的课程,为了让学员能更快的学习到语言、环境、框架和工具的使用,就在本地运行,用 demo 非常合适。 此时如果强行用线上环境,第一会扰乱学员的学习重点,第二是难度太大学员不易接受。 近几年是国内在线编程教育的高速发展阶段,但也是刚刚起步不久(回想 5 年之前,哪儿有那么多付费课程)。 正好近几年又是程序员行业发展壮大的关键时间,新人纷纷涌入。 所以,这段时间出现了大量的入门课程,各个平台,各个讲师,各个框架,各种“vue + 电商”的课程铺天盖地。以至于学员写简历,都写这些项目,面试官们应该有点印象。 在此,也就解答了本文一开始的问题“就讲一门课而已吗,还需要花钱?” —— 这是和我们大环境相关的。 进阶不再适合 demo 为啥进阶还要学习课程?而且花钱更多?—— 你上班的时候看看你身边的人,就知道了。 一块和你挤地铁的有多少人?一块和你堵车的有多少人?你上午占个厕所的坑位有多不容易?—— 就是因为人多,竞争激烈,不进则退呀! 我家人经常劝告我:别那么累了,慢着点干,你现在这么忙每月挣 xxx 钱,你歇着干每月挣个 70% 不也挺好的吗? 我说:这和你想的不一样,我现在这么干,每月挣 xxx ,我要稍微一懈怠,别说 70% 60% ,我一分钱都挣不到。因为大家都是一个集体,不再是自己种那一亩三分地了,你歇着干就会影响其他人,你就会被淘汰。大家想一下是不是这个道理? 好了,把话题拉回来。 所以,进阶的课程,我觉得不应该再用 demo ,要把标准提高,要能输出更有竞争力的内容。demo 和线上项目,哪个更有竞争力,这一点大家都知道。 真实项目有啥特别的,看功能和我做的 demo 一样啊? 举个例子。demo 就是实验室里的概念车,线上项目就是大街上跑的量产车。看着功能都一样,但本质有很大区别的。 加入要把这个概念车卖给你,你敢买吗?万一坏了零部件怎么办,有地方换吗?4S 店是否也有 10w 公里的质保?它作出碰撞测试吗,安全吗?它内饰做过甲醛等气体测试吗?它排量标准符合国家规定吗?它有出厂检测和 3C 证书吗?…… 同理,对于我们软件项目,demo 和线上项目也是有本质区别的。 demo 没有线上环境,如域名,服务器,数据库等 demo 没有上线、回滚的流程 demo 没有运维监控和报警,这些在实际工作中都是重点 demo 没有统计、分享等正式的业务场景 demo 不用考虑安全、攻击、敏感内容过滤等 demo 不用担心万一半夜出 bug 该怎么办? …… 还有很多,一次性说不完,都在课程里 上述这些,对于一个网站或者任何一个软件产品,是不是都非常重要?相信大家都懂得。但是这些都要借助线上项目,来讲出来,否则就是空口白说。 为啥很少见其他课程也用线上项目? 成本高啊,而且收益如何都还不知道呢~ 首先得像我,花钱买各种服务。而且现在服务器都不便宜,看看阿里云服务器,一年动辄 3k+ 。有人说可以买华为云、腾讯云 —— 是便宜,但做课程吗,还是要考虑找个大众的,这样容易理解。 再者,多了上线、回滚、运维、监控和报警、网络安全预防,这么多内容,自己的时间成本会增加很多。 但是,我还是做了这样的尝试,不试试怎么知道不行呢。 这些钱给报销吗? 😭很明显,不给报销。 发票都还没开呢,哪位需要的话,可以私信我。 现在各个平台,都没有给讲师报销服务器花费的机制。因为现在我没发现哪门课是在做一个正式的线上项目。PS:也或许有,只是我没发现。 即便是所谓的线上项目,最常见的形式,也就是平台给免费提供一个测试机,然后给一个二级甚至三级域名,能给学员演示一下。 毫不客气的说,全都是 demo 。 未来编程教育方向,之我见 第三次科技革命还在进行中,所有涉及的行业,都会越来越多元化、精细化。编程教育也是一样,各个技术栈,入门教程、进阶教程都会越来越精细。 而且,随着行业的发展,初期红利期结束,淘汰掉很多凑热闹的。课程会越来越贴合实际应用,越来越以产出实际价值为主,无论是入门的还是进阶的,学的就是工作中要用的到,有价值的东西。 基于以上两点,我还是坚信自己走的方向是正确的。 如果反馈不如预期的好,那可能是时机未到。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫张轩老师/":{"url":"pages/👨🏫张轩老师/","title":"👨🏫张轩老师","keywords":"","body":"张轩老师 - 课程分享 请直接看下级目录 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫张轩老师/01-在学习了一门技术的基础知识后,怎样持续提升这门技术达到更高水平?.html":{"url":"pages/👨🏫张轩老师/01-在学习了一门技术的基础知识后,怎样持续提升这门技术达到更高水平?.html","title":"在学习了一门技术的基础知识后,怎样持续提升这门技术达到更高水平?","keywords":"","body":"在学习了一门技术的基础知识后,怎样持续提升这门技术达到更高水平? 因为很多同学学习技术陷于一个瓶颈,尤其是很多在中小型公司的同学,发现工作中每天都深陷重复业务的泥潭,不由的产生一种恐慌的心情,觉得自己在浪费时间没有提高。很多同学都向我要求的复杂前端项目和高级课程。 什么是复杂项目 那么什么是复杂项目呢?一个陈年老项目有10w+代码 ? 一个增删改查项目有 50 个分开的页面算复杂吗?虽然它的代码量够大,但是它更不称不上复杂。反而会让人很有挫败感和无力感。 我认为想真正尝试复杂的项目的必须要是一个现代的前端开发项目,涉猎多个不同领域: 交互的复杂性 - 可能包含元素的复杂交互 移动,拖动大小,拖动排序 等。 数据状态的复杂性 - 嵌套数据和多种类型的组件相对应,同时两者要互相同步。 多项目之间的依赖性 - 有可能要抽取出一系列的公共库供多个项目使用。 测试 - 保证代码质量,减少 Bug 的必备技能。 打包 - 对应不同类型的功能的项目(web 应用或者是 library),怎样生成多种类型对应的可复用的代码格式。 性能优化 - 大型项目性能是要点,让加载速度提升就等于省的是真金白银。 第三方库使用和二次开发 - 怎样快速找到和使用已经有的技术方案解决特定问题。 持续集成 - 让代码能够自动化的测试,部署,是去大厂的敲门砖。也是大型项目必备的内容。 ... 只有满足了这样需求的项目才能把前端开发的方方面面都包含在其中,才能掌握其中的复杂项目的奥义。 写出高质量符合大厂要求的代码 除了项目,代码质量也是一块需要考量的因素。 很多人都知道大厂镀金是个对于每个人的职业都是重要的一环,但是很多在中小心公司的同学都不熟悉大厂开发的流程和要求,有的人甚至经常是公司的“全干工程师”,从前端到后端都是一个人说了算。大厂由于工程师众多,必须采取一套标准化自动高效的流程来管理代码和部署以及测试。 简单可以描述为: 从 git flow 分支的创建,管理已经合并 到 lint 工具保证代码的格式正确 到 单元测试 尽可能保证代码的质量 到 代码提交 尽可能详尽可追溯的提交信息, 到 PR review,再次保证代码的质量 到最后 CI/CD ,保证持续迭代和部署等等。 这些概念如果你觉得陌生,一两句话很难说的清楚,那么就需要通过一个大型多人协作的项目去真是的实践这些过程。软件开发肯定会伴随着 Bug 的出现,关键是怎样使用科学和优良的实践来尽可能的发现和规避风险。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "},"pages/👨🏫张轩老师/02-Typescript 是不是前端开发必备的技能?一个 ts 黑到 ts 粉的心路历程.html":{"url":"pages/👨🏫张轩老师/02-Typescript 是不是前端开发必备的技能?一个 ts 黑到 ts 粉的心路历程.html","title":"Typescript 是不是前端开发必备的技能?一个 Ts 黑到 Ts 粉的心路历程","keywords":"","body":"Typescript 是不是前端开发必备的技能?一个 ts 黑到 ts 粉的心路历程 2020年 Typescript 各种火,就像我之前说的在 jsconf 2019上,typescript 也变成了一个主要议题,占到了很大比重,来自微软的讲师韩骏还拿出了这么一张图,来表达自己的观点, 我觉得这个不是夸大其词,而实实在在的是一个趋势,来自 2018 年 stateofjs 权威调查显示,80% 的程序员都希望在新的项目中学习和使用 typescript。大家可以明显看到从 2016 年到 2018年 这个趋势的绝大变化,这就说明 typescript 越来越流行了。 在我的编程生涯到现在,我一直在使用动态类型语言(Dynamically Typed Language),聊起这个概念,那就要说说 动态类型语言 和他的对立面 - 静态类型语言(Statically Typed Language)。我刚写 typescript 的时候,对类型声明嗤之以鼻,添加一大堆类型浪费我宝贵的时间,还时不时遇到根本看不懂的类型错误,感觉很抓狂,我当时想对 ts 编译器说:“老子能管好自己写的类型,不用你报错”,实在搞不定的类型错误发生的时候,我就会使用 any 大法,完全是一副应付差事的用法。 我当时维护的项目是一个十几万行的大型项目,当时还在推另外一个小型项目,我极力反对 typescript,据理力争,“你是想让我赶快完成任务?还是浪费时间在写 any 上面?这玩意儿根本就不能给你避免 Bug,都是扯犊子。” 后来我花更多的时间在老项目上面,我每天写 any 发 PR 被老外一阵喷。这时候可不能给自己丢脸啊,我开始认真对待起 type 来。 我发现当我在代码中打入了越来越多类型的时候,效率居然变得很高(自动补全),遇到各种傻瓜错误(比如说 typo,我的单词记不住,经常打错 )的几率也越来越少,在后来两年的工作生涯中,我在很多比较大型的项目中都使用了它,并且越来越感受到它的优势。虽然精通 ts 真的有一定的难度,但是其实你也不必那么精通,能差不多看懂,帮你提高效率就好了,我总结几点编码过程中,实实在在帮助到我的点。 1 程序更容易理解 当我们进行编码的时时候,我们非常关心这几个问题,一个函数或者方法接受什么样什么类型的参数,它的返回值和类型是什么?有什么其他外部数据需要被引进?为了解决这几个问题,我们一般都要详细的查阅文档,搞清楚所有的来龙去脉,因为动态语言的约束我们很难完成这几项任务,我们需要在代码真正运行的时候来调试才能知道答案,比如说加断点或者 console.log 去查看输出,甚至还需要社交过程,我有好几次都是直接跑去问同事或者blame原来写这段代码的人,发个邮件问这些代码究竟是干嘛的,扯皮扯个好几天。有了 typescript,这几个问题都迎刃而解,代码就是全部的注释,通过代码你不再需要去进行猜测,而是直接就可以知道这些问题的答案。看下面上古神器 jQuery 的提示,这参数,返回值的说明,还有文档地址和代码示例,这水平比你百度出来不知几百年前的csdn博客文章不知道高到哪里去了。 2 效率更高 有了 IDE 和 compiler 的帮助,你可以非常方便的在不同的代码块和定义之间进行跳转,同时进行代码补全,还有丰富的接口提示,可以是事半功倍。我就享受这个感觉,能让 IDE 炫酷的提示是每个程序员的梦想。可以疯狂的体验下“老夫就是 jQuery 一把梭”的快感。 3 更少的错误 在编译期间能够发现大部分的错误,这远远要比运行时候再出现这些错误要好的多。在 typescript 之前,我不知道有多少次出现变量名称打错这种错误,传入错误类型的参数,还有就是还有就是排在前端错误第一名:最经典的“Cannot read property 'xxx' on undefined:无法在 undefined 上读取 xxx 属性,通常出现在 a.b.c 的情况。” 4 非常好的包容性 typescript 是 javascript 超集,即使我们把 js 文件直接命名为 ts 文件,也不会有任何的问题,兼容第三方库,即使这些库没有用 ts 编写,也可以给他们编写单独的类型文件进行读取。大部分非常流行的库都用 typescript 实现或者提供写好的类型文件供开发者使用,比如 React,vue,angular,和 ant design 等等,使用起来可谓是无缝衔接。 5 提高自身水平 ts 内部有非常多的内置对象,这些对象我们平时在使用的时候都没有过多的在意,比如 NodeList 和 HTMLCollection 的异同,Event 对象,衍生出来的 MouseEvent,TouchEvent 都有啥区别和属性 等等。。。 把这些接口都一一搞清楚以后,对BOM 和 DOM 的机制了解可以达到另外一个境界,潜移默化的就变成了 API 使用高手。当别人看到没用过的属性的时候,你可以骄傲的化身 API 达人。 结论: 假如你工作在一个大中型项目上面,typescript 对你应该是利大于弊。可以学!还能从另外一个方便了解静态类型语言是怎么玩的,看到别人的 Java 代码居然能有看得懂的部分了。 当然要学会根据自己的需求和项目的规模合理选用工具,如果你的应用就是一个简单的展示页面,加几个 UI 状态改变,就没有必要使用。 Copyright © zy (2020 - present) all right reserved,powered by GitbookFile Modify: 2023-06-16 05:10:58 "}}