从0到大论前端持续集成

什么是持续集成?

DevOps 是一种软件开发方法。它将持续开发、持续测试、持续集成、持续部署和持续监控贯穿于软件开发的整个生命周期。
image.pngCI 代表持续集成(Continuous Integration),CD 代表持续交付(Continuous Delivery)和持续部署(Continuous Deployment)。也可以将它们看作是类似于软件开发生命周期的过程。

image.png

  • 在CI环境中,开发人员将会频繁地向主干提交代码。这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试(通常是单元测试和集成测试)流进行验证。
  • 在CD环境中,通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,任何修改通过了所有已有的工作流就会直接和客户见面,只有当一个修改在工作流中构建失败才能阻止它部署到产品线。
  • 持续交付的英文全称是:Continuous delivery,缩写也是CD,它是一种软件工程手法。它可以让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以释出的状况。它的目标在于让软件的建置、测试与释出变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。

自动化构建工具,编译、部署、测试、监控、本机开发上线环境。
FIS3/Webpack/jdists/package.json/chai/supertest/mocha/selenium-webdriver
持续集成平台。 Jenkins、Travis CI、Buddy
部署工具。 rsync、shelljs、yargs
实践参考《如何从零开始搭建 CI/CD 流水线》

什么是统一代码仓库多分支开发?

image.png
master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。
Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0v2.0 等等)。
一个可发布版本提交到git仓库的🌰

  1. var shell = require('shelljs');
  2. //判定git命令是否可用
  3. if (!shell.which('git')) {
  4. //向命令行打印git命令不可用的提示信息
  5. shell.echo('Sorry, this script requires git');
  6. //退出当前进程
  7. shell.exit(1);
  8. }
  9. //先删除'out/Release'目录
  10. shell.rm('-rf', 'out/Release');
  11. //拷贝文件到'out/Release'目录
  12. shell.cp('-R', 'stuff/', 'out/Release');
  13. //切换当前工作目录到'lib'
  14. shell.cd('lib');
  15. //shell.ls('*.js')返回值是一个包含所有js文件路径的数组
  16. shell.ls('*.js').forEach(function(file) {//遍历数组
  17. //sed命令用于文件内容的替换,这里是对每个文件都执行如下3步操作,更改版本信息
  18. shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
  19. shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
  20. shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
  21. });
  22. //切换当前工作目录到上一层
  23. shell.cd('..');
  24. //同步执行git命令提交代码
  25. if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
  26. shell.echo('Error: Git commit failed');
  27. shell.exit(1);
  28. }

实践:快速创建分支, 快速创建组件

什么是前端工程化?

前端模块化(模块管理、资源加载)

模块化的工程意义首先在于分治的思想,对功能进行分治,有利于我们的维护;其次是复用,有利于我们的开发。

分而治之:将一个大问题分解成多个较为独立的与原问题性质相同的小问题,将所有的小问题的解答组合起来即可得到大问题的答案。

[p3]前端架构构建系列(上) - 图5 AMD (Asynchronous Module Definition,异步模块定义)。 AMD提倡依赖前置,在定义模块的时候就要声明其依赖的模块。实践requirejs

  1. define(['dep1','dep2'],function(dep1,dep2){
  2. //内部只能使⽤用指定的模块
  3. return function(){};
  4. });

CMD (Common Module Definition,通用模块定义)。CMD提倡就近依赖(按需加载)。实践SeaJS

  1. define(function(require,exports,module){
  2. //此处如果需要加载某XX模块,可以引⼊入
  3. var xx=require(‘XX’);
  4. });

CommomJS规范。通过require,module.exports,exports来进行导入和导出,这里exports是module.exports的一个引用。
ES6 import export/export default
关于webpack:
1.Webpack执行CommonJS标准,解决了依赖配置和请求流量。
2.对于Webpack来讲万物都可以是模块,所有的文件都被合并到JS中,最终在浏览器。
3.兼容AMD与CMD。
4.JS模块化不仅仅为了提高代码复用性,更是为了让资源文件更合理地进行缓存。

前端开发组件化。

image.png
1.每一个前端模块都是一个小项目,配合mock.js可以进行本地的开发测试,package.json是标配产物。经过webpack的环境配置统一进行本地环境、上线环境的编译过程。
2.由page组装widget,由widget组装WebComponents(X-TAG)。
3.能够根据路由快速抉择配置SPA或者直出。
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。 [p3]前端架构构建系列(上) - 图7Custom Elements, 提供一种方式让开发者可以⾃定义 HTML 元素,包括特定的组成,样式和行为。

  1. class ButtonHelloElement extends HTMLButtonElement {
  2. constructor() {
  3. super()
  4. this.addEventListener('click', () => {
  5. alert('hello world')
  6. })
  7. }
  8. }
  9. customElements.define('button-hello', ButtonHelloElement, { extends: 'button' })

HTML Templates, 用过 handlebars 的人都知道有这么一个东西:。那么 HTML Templates 便是把这个东西官⽅标准化,提供了一个 template 标签来存放以后需要但是暂时不渲染的 HTML 代码。

  1. <template id="template">
  2. <p>Smile!</p>
  3. </template>
  4. <script>
  5. let num = 3;
  6. const fragment =document.getElementById('template').content.cloneNode(true);
  7. while (num-- > 1) {
  8. fragment.firstChild.before(fragment.firstChild.cloneNode(true));
  9. fragment.firstChild.textContent += fragment.lastChild.textContent;
  10. }
  11. document.body.appendChild(fragment);
  12. </script>

Shadow DOM 最本质的需求是需要一个隔离组件代码作用域的东西,例如我组件代码的 CSS 不能影响其他组件之类的,而iframe ⼜太重并且可能有各种奇怪问题。旨在提供⼀种更好地组织⻚面元素的方式,来为日趋复杂的⻚面应用提供强大支持,避免代码间的相互影响。

  1. <div id="app"></div>
  2. <script>
  3. const div = document.getElementById('app')
  4. const shadowRoot = div.createShadowRoot()
  5. const span = document.createElement('span')
  6. span.textContent = 'hello world'
  7. shadowRoot.appendChild(span)
  8. </script>

截屏2020-05-04下午4.13.32.png
HTML Imports 旨在成为 Web Components 的打包机制,但也可以单独使用 HTML Imports。

自动化编译

在前端开发中,我们总是会去使用很多工具、手段来优化代码、提升开发效率,例如,我们会使用sass、less等CSS预处理工具来编写更好维护的样式代码,我们也会使用CSSLint、eslint等代码检查工具来检查代码的语法错误,使用文件合并压缩等手段来减少资源大小,除此之外我们还会去做雪碧图合并、多倍图处理、字体压缩处理、代码发布等等。自动化编译流程:
foo.es -> require(‘foo.scss’) -> background:url(foo.png)
-> 读入foo.es的文件内容,编译成js内容
-> 分析js内容,找到资源定位标记 ‘foo.scss’
-> 对foo.scss进行编译:
-> 读入foo.scss的文件内容,编译成css内容
-> 分析css内容,找到资源定位标记 url(foo.png)
-> 对 foo.png 进行编译:
-> 读入foo.png的内容
-> 图片压缩
-> 返回图片内容
-> 根据foo.png的最终内容计算md5戳,替换url(foo.png)为url(/static/img/foo_2af0b.png)
-> 替换完毕所有资源定位标记,对css内容进行压缩
-> 返回css内容
-> 根据foo.css的最终内容计算md5戳,替换’foo.scss’为 ‘/static/scss/foo_bae39.css’
-> 替换完毕所有资源定位标记,对js内容进行压缩
-> 返回js内容
-> 根据最终的js内容计算md5戳,得到foo.coffee的资源url为 ‘/static/scripts/foo_3fc20.js’

静态资源管理(静态资源版本更新与缓存)

1.配置超长时间的本地缓存 — 节省带宽,提高性能
2.采用内容摘要作为缓存更新依据— 精确的缓存控制
3.静态资源CDN部署—— 优化网络请求
4.更资源发布路径实现非覆盖式发布 — 平滑升级

1.FIS3根据分析好的文件包,利用HOOK插件//分析下FIS的生成的配置文件
FIS3 是面向前端的工程构建工具。解决前端工程中性能优化、资源加载(异步、同步、按需、预加载、依赖管理、合并、内嵌)、模块化开发、自动化工具、开发规范、代码部署等问题。
2.Webpack在开发阶段打包,利用插件分析处直接提取。FileLoader&&extract-textwebpack-plugin。
3.配置publicpath分发到CDN.

什么是自动化构建?

发布npm包

1.添加用户: npm adduser
2.登录用户: npm login
3.升级补丁版本号:npm version patch
4.升级小版本号:npm version minor
5.升级大版本号:npm version major
6.发布版本:npm publish

更多自动化!

1.自动化运营平台
2.自动化雪碧图
3.自动化离线打包
4.自动化控制缓存级别
5.自动化处理Inline
6.自动化根据网速分发版本资源
7.自动化运维平台
END 2020-5-1