第一章 周介绍


1-1 整体内容介绍

  • 前端组件演讲过程和大厂前端物料体系介绍
  • 组件复用体系架构设计
  • 脚手架组件创建+发布全流程实现

第二章 大厂物料体系介绍和前端组件平台架构设计


2-1 大厂前端物料体系介绍

2-2 组件平台架构设计

点击查看【processon】

第三章 脚手架组件创建和预览项目开发


3-1 新的组件库模板开发


1. 发布npm包

  • 下载源至某处:https://git.imooc.com/class-110/lego-bricks
  • 新建文件 cloudscope-cli-components
  • cd cloudscope-cli-components
  • npm init -y
  • 将源码移动到 cloudscope-cli-components下,并将lego-bricks改名为template
  • cloudscope-cli-components/package.json下,添加publishConfig

    1. {
    2. "name": "cloudscope-cli-components",
    3. "version": "1.0.2",
    4. "description": "",
    5. "keywords": [],
    6. "author": "",
    7. "license": "ISC",
    8. "publishConfig": {
    9. "access": "public"
    10. }
    11. }
  • cloudscope-cli-components/template/package.json下,添加files

    1. "files": [
    2. "build",
    3. "src",
    4. "tests",
    5. "dist",
    6. ".browserslistrc",
    7. ".eslintrc.js",
    8. ".gitignore",
    9. ".travis.yml",
    10. "babel.config.js",
    11. "jest.config.js",
    12. "README.md",
    13. "tsconfig.json"
    14. ],
  • npm publish

  1. 维护mongodb,添加一条数据

    1. {
    2. "_id" : ObjectId("612473d8e1694b2c0191177f"),
    3. "name" : "通用的Vue3组件库模版",
    4. "npmName" : "cloudscope-cli-components",
    5. "version" : "1.0.1",
    6. "type" : "normal",
    7. "installCommand" : "npm install --registry=https://registry.npm.taobao.org",
    8. "startCommand" : "npm run serve",
    9. "tag" : [
    10. "component"
    11. ],
    12. "ignore" : [
    13. "**/public/**",
    14. "**.png"
    15. ]
    16. }
  2. 新建components-test目录

    cloudscope-cli init -tp /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/init

3-2 组件库预览项目开发

这节听的有点懵逼,上一节,通过cloudscope-cli init了一个命令后,

  • npm run build
  • 根目录下继续新建examples目录,cd examples
  • vue create examples
  • cd examples中
  1. //main.js
  2. import LegoComponents from "../../../dist/component-test.esm";
  3. createApp(App).use(LegoComponents).mount('#app')
  4. //App.vue
  5. <template>
  6. <div id="app">
  7. <l-image src="https://img.mukewang.com/5d5e51f900011f0c06550501-100-100.jpg"></l-image>
  8. </div>
  9. </template>
  10. //vue.config.js
  11. module.exports = {
  12. publicPath:'./'
  13. }

最后继续 npm run build,打开dist目录下的index.html,查看页面效果

3-3 组件多预览模式开发

有点小懵逼,组件库就开发完毕了

  1. module.exports = {
  2. publicPath:'./',
  3. pages:{
  4. index:{
  5. entry:'./src/main.js',
  6. templates:'./public/index.html'
  7. },
  8. index2:{
  9. entry:'./src/main2.js',
  10. templates:'./public/index.html'
  11. },
  12. }
  13. }

3-4 将预览功能集成到组件库模板

3-5 组件初始化时自动生成配置文件

3-6 组件库命名优化

第四章 脚手架组件发布流程开发


4-1 组件仓库初始化流程优化

cloudscope-cli 本章相关代码提交至 cloudscope-cli/lesson32

本节主要为对仓库名称带有·@·进行一个合法的名字修改

  1. // cloudscope-cli/models/git/lib/index.js
  2. class Git {
  3. constructor({name, version, dir},{
  4. ^^^^^^^
  5. if(name.startsWith('@') && name.indexOf('/')>0){
  6. const nameArray = name.split('/')
  7. this.name = nameArray.join('_').replace('@','')
  8. }else{
  9. this.name = name //发布项目名称
  10. }
  11. }
  12. }

4-2 组件上传前预检查流程开发

cloudscope-cli 本章相关代码提交至 cloudscope-cli/lesson32

  1. // cloudscope-cli/models/git/lib/index.js
  2. async prepare(){
  3. await this.checkComponent() // 组件合法性检查
  4. }
  5. async checkComponent(){
  6. let componentFile = this.isComponent()
  7. if(componentFile){
  8. log.info('开始检查build结果')
  9. if(!this.buildCmd){
  10. this.buildCmd = 'npm run build'
  11. }
  12. require('child_process').execSync(this.buildCmd,{
  13. cwd:this.dir
  14. })
  15. const buildPath = path.resolve(this.dir,componentFile.buildPath)
  16. if(!fs.existsSync(buildPath)){
  17. throw new Error(`构建结果:${buildPath}不存在!`)
  18. }
  19. const pkg = this.getPackageJson()
  20. if(!pkg.files || !pkg.files.includes(componentFile.buildPath)){
  21. throw new Error(`packages.jsonfiles属性未添加构建结果目录:[${componentFile.buildPath}],请在packag.json中收到添加`)
  22. }
  23. log.success('build结果检查通过!')
  24. }
  25. }
  26. isComponent(){
  27. const componentFilePath = path.resolve(this.dir,COMPONENT_FILE);
  28. return fs.existsSync(componentFilePath) && fse.readJsonSync(componentFilePath)
  29. }

4-3 组件发布前准备工作开发

cloudscope-cli 本章相关代码提交至 cloudscope-cli/lesson32

  1. async publish(){
  2. let ret = false;
  3. if(this.isComponent()){
  4. log.info('开始发布组件')
  5. await this.saveComponentToDB()
  6. }else{
  7. ………………
  8. }
  9. if (this.prod && ret) {
  10. await this.uploadComponentToNpm()
  11. this.runCreateTagTask();
  12. }
  13. async saveComponentToDB(){
  14. // 将组件信息上传至数据库-RDS
  15. // 将组件多预览页面上传至OSS
  16. }
  17. async uploadComponentToNpm(){
  18. // 完成组件上传至npm
  19. }

4-4 创建RDS组件表+后端MySQL插件集成

cloudscope-cli-server 本章相关代码提交至 cloudscope-cli-server/lesson32

本章主要是在服务端链接mysql数据库,并做相关测试 编写相关代码前:cnpm i -S egg-mysql

  1. // app/config/db.js
  2. const MYSQL_HOST = 'liugezhou.com'
  3. const MYSQL_PORT = 3306
  4. const MYSQL_USER = 'root'
  5. const MYSQL_PWD = fs.readFileSync(path.resolve(userHome,'.cloudscope-cli','mysql_pwd')).toString().trim()
  6. const MYSQL_DB ='imooc_web_architect_cli'
  7. //app/config/plugin.js
  8. exports.mysql = {
  9. enable:true,
  10. package: 'egg-mysql'
  11. }
  12. //app/config/config.default.js
  13. config.mysql = {
  14. client: {
  15. host: MYSQL_HOST,
  16. port: MYSQL_PORT,
  17. user:MYSQL_USER,
  18. password:MYSQL_PWD,
  19. database:MYSQL_DB
  20. },
  21. app:true,
  22. agent:false
  23. }
  24. //相关测试代码
  25. // app/app/router.js
  26. router.get('/mysql',controller.project.mysqlTest)
  27. // app/controller/project.js
  28. async mysqlTest(){
  29. const {ctx, app } = this
  30. const list = await app.mysql.select('component')
  31. ctx.body = JSON.stringify(list)
  32. }

4-5 组件上传数据库准备工作开发

cloudscope-cli 本章相关代码提交至 cloudscope-cli/lesson32

  1. // models/git/lib/index.js
  2. const ComponentRequest = require('../lib/ComponentRequest');
  3. async saveComponentToDB(){
  4. // 将组件信息上传至数据库-RDS
  5. log.info('上传组件信息至OSS+写入数据库')
  6. const componentFile = this.isComponent()
  7. let componentExamplePath = path.resolve(this.dir,componentFile.examplePath);
  8. let dirs = fs.readdirSync(componentExamplePath)
  9. if(dirs.includes('dist')){
  10. componentExamplePath = path.resolve(componentExamplePath,'dist')
  11. dirs = fs.readdirSync(componentExamplePath)
  12. componentFile.examplePath = `${componentFile.examplePath}/dist`
  13. }
  14. dirs = dirs.filter(dir => dir.match(/^index(\d)*.html$/))
  15. componentFile.exampleList = dirs
  16. componentFile.exampleRealPath = componentExamplePath
  17. const data = await ComponentRequest.createComponent({
  18. component:componentFile,
  19. git: {
  20. type: this.gitServer.type,
  21. remote: this.remote,
  22. version: this.version,
  23. branch: this.branch,
  24. login: this.login,
  25. owner: this.owner,
  26. },
  27. })
  28. if (!data) {
  29. throw new Error('上传组件失败');
  30. }
  31. // 2.将组件多预览页面上传至OSS
  32. return true;
  33. }
  34. // models/git/lib/ComponentRequest.js
  35. const axios = require('axios');
  36. const log = require('@cloudscope-cli/log');
  37. module.exports = {
  38. createComponent: async function(component) {
  39. try {
  40. const response = await axios.post('http://liugezhou.com:7001/api/v1/components', component);
  41. log.verbose('response', response);
  42. const { data } = response;
  43. if (data.code === 0) {
  44. return data.data;
  45. }
  46. return null;
  47. } catch (e) {
  48. throw e;
  49. }
  50. },
  51. };

4-6 组件上传restful api开发

cloudscope-cli-server 本章相关代码提交至 cloudscope-cli-server/lesson32

  1. // app/constant.js
  2. module.exports = {
  3. STATUS: {
  4. ON: 1,
  5. OFF: 0,
  6. },
  7. }
  8. // app/router.js
  9. router.resources('components', '/api/v1/components', controller.v1.components);
  10. // app/Controller/v1/Components.js
  11. 'use strict'
  12. const Controller = require("egg").Controller;
  13. const constant = require('../../constant');
  14. const ComponentService = require('../../service/ComponentService');
  15. class ComponentsController extends Controller {
  16. // api/v1/components
  17. async index() {
  18. const { ctx } = this;
  19. ctx.body = 'get component'
  20. }
  21. // api/v1/components/:id
  22. async show() {
  23. const { ctx } = this;
  24. ctx.body = 'get single component'
  25. }
  26. // post data
  27. async create() {
  28. const { ctx, app } = this;
  29. const { component, git } = ctx.request.body;
  30. const timestamp = new Date().getTime()
  31. // 1. 添加组件信息
  32. const componentData = {
  33. name: component.name,
  34. classname: component.className,
  35. description: component.description,
  36. npm_name: component.npmName,
  37. npm_version: component.npmVersion,
  38. git_type: git.type,
  39. git_remote: git.remote,
  40. git_owner: git.owner,
  41. git_login: git.login,
  42. status: constant.STATUS.ON,
  43. create_dt: timestamp,
  44. create_by: git.login,
  45. update_dt: timestamp,
  46. update_by: git.login,
  47. };
  48. const componentService = new ComponentService(app);
  49. ctx.body = 'create component'
  50. }
  51. }
  52. module.exports = ComponentsController

4-7 组件上传数据库逻辑开发

  1. // app/service/ComponentService.js
  2. 'use strict'
  3. class ComponentService {
  4. constructor(app){
  5. this.app = app,
  6. this.name = 'component'
  7. }
  8. async queryOne(query){
  9. const data = await this.app.mysql.select(this.name, {
  10. where: query,
  11. });
  12. if (data && data.length > 0) {
  13. return data[0];
  14. }
  15. return null;
  16. }
  17. async insert(data) {
  18. const res = await this.app.mysql.insert(this.name, data);
  19. return res.insertId;
  20. }
  21. }
  22. module.exports = ComponentService
  23. //app/service/versionService.js
  24. 'use strict'
  25. class VersionService {
  26. constructor(app) {
  27. this.app = app;
  28. this.name = 'version'
  29. }
  30. async queryOne(query) {
  31. const data = await this.app.mysql.select(this.name, {
  32. where: query,
  33. });
  34. if (data && data.length > 0) {
  35. return data[0];
  36. }
  37. return null;
  38. }
  39. async insert(data) {
  40. const res = await this.app.mysql.insert(this.name, data);
  41. if (res.affectedRows > 0) {
  42. return true;
  43. }
  44. return false
  45. }
  46. async update(data, query) {
  47. const res = await this.app.mysql.update(this.name, data, {
  48. where: query
  49. })
  50. if (res.affectedRows > 0) {
  51. return true;
  52. }
  53. return false
  54. }
  55. }
  56. module.exports = VersionService
  57. //app/controller/v1/Components.js
  58. async create() {
  59. const { ctx, app } = this;
  60. const { component, git } = ctx.request.body;
  61. const timestamp = new Date().getTime()
  62. // 1. 添加组件信息
  63. const componentData = {
  64. name: component.name,
  65. classname: component.className,
  66. description: component.description,
  67. npm_name: component.npmName,
  68. npm_version: component.npmVersion,
  69. git_type: git.type,
  70. git_remote: git.remote,
  71. git_owner: git.owner,
  72. git_login: git.login,
  73. status: constant.STATUS.ON,
  74. create_dt: timestamp,
  75. create_by: git.login,
  76. update_dt: timestamp,
  77. update_by: git.login,
  78. };
  79. const componentService = new ComponentService(app);
  80. const haveComponentInDB = await componentService.queryOne({
  81. className: component.className
  82. })
  83. let componentId;
  84. if (!haveComponentInDB) {
  85. componentId = await componentService.insert(componentData);
  86. } else {
  87. componentId = haveComponentInDB.id
  88. }
  89. if (!componentId) {
  90. ctx.body = failed('添加组件失败')
  91. }
  92. // 2.添加组件版本信息
  93. const versionData = {
  94. component_id: componentId,
  95. version: git.version,
  96. build_path: component.buildPath,
  97. example_path: component.examplePath,
  98. example_list: JSON.stringify(component.exampleList),
  99. status: constant.STATUS.ON,
  100. create_dt: timestamp,
  101. create_by: git.login,
  102. update_dt: timestamp,
  103. update_by: git.login,
  104. }
  105. const versionService = new VersionService(app);
  106. const haveVersionInDB = await versionService.queryOne({
  107. component_id: componentId,
  108. version: git.version
  109. });
  110. if (!haveVersionInDB) {
  111. const versionRes = await versionService.insert(versionData)
  112. if (!versionRes) {
  113. ctx.body = failed('添加组件失败')
  114. }
  115. } else {
  116. const updateData = {
  117. build_path: component.buildPath,
  118. example_path: component.examplePath,
  119. example_list: JSON.stringify(component.exampleList),
  120. update_dt: timestamp,
  121. update_by: git.login,
  122. };
  123. const versionRes = await versionService.update(updateData, {
  124. component_id: componentId,
  125. version: versionData.version,
  126. });
  127. if (!versionRes) {
  128. ctx.body = failed('更新组件失败');
  129. return;
  130. }
  131. }
  132. }

4-8 组件NPM发布逻辑开发

本节主要是调试过多,重要几行代码为在脚手架 cloudscope-cli中添加NPM发布逻辑

  1. async uploadComponentToNpm() {
  2. // 完成组件上传至npm
  3. if (this.isComponent()) {
  4. log.info('开始发布组件NPM')
  5. require('child_process').execSync('npm publish', {
  6. cwd: this.dir
  7. })
  8. log.success('组件NPM发布成功')
  9. }
  10. }

4-9 组件自动生成远程仓库Tag问题解决

End