fouber / blog

没事写写文章,喜欢的话请点star,想订阅点watch,千万别fork!
22.64k stars 2.37k forks source link

欢迎一起探讨各自在前端开发中遇到的工程问题 #8

Closed fouber closed 2 years ago

fouber commented 9 years ago

恩,这个repos虽然命名是blog,一开始也定义为我的个人博客,但感觉光我一个人码字也挺空虚寂寞冷的,所以希望有在前端工程方面遇到问题,或者有所感悟,或者有所实践的同学,可以尽情在issues里开启话题来与大家分享交流,有个比较集中的地方讨论有关前端方面的工程问题也挺好的不是~~

asmoker commented 9 years ago

遇到的问题: 我用的grunt的usemin插件,由于后端映射的路径跟项目结构的物理路径不同,所以html中js、css和图片的引用路径都是按映射的路径写的,但是采用usemin处理html这些资源的链接的时候是按物理路径去更改的,请问大家有什么好的方法吗?

大致结构是这样:

project/
├── css
│   └── index.css
├── html
│   └── index.html
├── img
│   └── index.png
└── js
    └── index.js

映射结果:

http://localhost:8080/index.html http://localhost:8080/css/index.css

这样,所以在index.html中引入js路径为 src="js/index.js",而在物理路径下应该是src="../js/index.js",所以在用usemin的时候会找不到资源文件导致无法修改静态资源路径。

注:我的解决方案是先把html文件夹下的所有内容先copy到project目录下,usemin执行完成后再clean掉,感觉比较笨。

fouber commented 9 years ago

@zmpandzmp grunt的话如果既要保持工程路径的书写方式,又要跟线上部署映射起来,就只能暴力的在构建中处理了。。。

如果是fis的话,可以直接配置任意文件的发布属性,书写的时候始终是工程中的相对路径,构建时会根据用户配置替换对应的地址。

jincdream commented 9 years ago

@nimojs 我现在用的 loader 是自己基于 scrat.js 那套思想构建的。太挫了就不放出来了。可以参考scrat.jsscrat 构建工具

asmoker commented 9 years ago

@fouber 上述的路径映射问题用grunt的copy和clean的方法解决了一部分,因为今天弄了一下,发现有些公用的common.css中,因为所有的html文件都要用到且html文件层级不确定,所以在commons.css中引用的图片url都采用了决定路径url(/img/index.jpg)的形式,上述copy和clean的解决方案又解决不了啦。%>_<% 感觉grunt好坑。 难道要自定义方法替换url吗? 😭

fouber commented 9 years ago

@zmpandzmp

把所有相对路径替换成构建后的绝对路径,这是保证资源定位准确最简单最可靠的做法了。这个过程确实需要支持自定义url,因为工程目录可能跟部署目录不同,构建工具要有url替换的依据,这些应该是必然要实现的。。。

PeterRao commented 9 years ago

@fouber 云龙大大,一直看你文章收益匪浅,这边我一直也在研究前端工程化方面。现在公司部署了一套自动构建与发布方案,但上面图中UAE那块(也就是代码推送这块),并没有思路,能否具体介绍下。系统监控方面也很想了解目前你们团队的大致方案。

fouber commented 9 years ago

@PeterRao

开发流程方面,至少涉及四个平台:

  1. 代码托管
  2. 持续集成
  3. 代码库
  4. 运维操作

『代码托管平台』主要是git/svn的托管平台,现在应该很多人在用 gitlab,用这类平台的主要目的是利用其中的『hook』功能,就是可以在这类平台上设置代码提交之后要做哪些操作,这样我们可以在开发者提交代码之后把提交信息推送到持续集成平台。

『持续集成平台』常用来做自动构建和测试,主流的是 Jenkins CIGitlab CI ,代码托管平台发现有代码提交之后,会把提交信息推送到持续集成平台,持续集成平台会根据提交信息拉取指定的git/svn分支,然后根据开发者在平台上的配置对项目进行自动化构建和测试,然后把构建后的代码打个tar.gz包推送到代码库存储起来。

『代码库平台』其实就是一个存储持续集成平台每次构建结果的地方,根据构建时间来存放,这样运维操作平台在部署的时候就可以从代码库拉取代码进行上线部署了。

『运维操作平台』主要的工作就是从代码库拉取指定的代码部署到指定的环境中。这些一般需要开发者操作,这里一般会有『上线单』的概念,每次发布前配置一份上线单,包括上线版本,上线说明,指定拉取的代码库中哪个代码包,部署到哪些机器上,部署顺序等。每个上线单可以视为一个部署版本,遇到问题需要回滚的时候直接重新执行之前稳定时期的上线单就行了。

开发者提交代码后,整个持续集成的自动化的流程为:

开发者:git push
  → 代码托管平台:hook
    → 持续集成平台:build && test && tar && push
      → 代码库:save

部署过程就是:

运维操作平台:
   * 创建上线单
   * 说明部署原因
   * 指定代码库的包(从代码库拉取)
   * 指定部署机器
   * 启动部署
   * 记录上线单
   * 回滚

一个完整的自动化流程我感觉至少需要上述4个节点,其中前三个可以由前端自行组建,找个限制的台式机,配置好一点,装一个linux系统,撘gitlab、jenkins,jenkins自带归档功能(程序包列表),可以省掉代码库平台。与运维平台的打通(主要是代码库的接入部分)就要和你们的运维团队协商完成了,这个通常都不是什么难事。

不推荐由持续集成平台直接推送构建结果到运维然后自动部署,这种方式非常危险,所以一定要有代码库,能记录历史版本,找到备份,方便回滚,而且运维操作是主动拉取代码,不是被动推送,增加了安全性

PeterRao commented 9 years ago

@fouber 谢谢云龙大大的回复,说的非常详细,我自己把前三部分搭建起来,不过部署还是通过持续集成平台推送的,我也一直觉得是个安全隐患,但目前由于运维人手不够比较忙,等运维抽时间规划下。还有一个系统监控的问题,目前我是自己查看日志去定位一些静态资源访问和接口调用的问题,想请教下云龙大大关于日志的分析,以及 js 错误收集方案,有好的工程化建议嘛?

noonhorse commented 9 years ago

mark

fouber commented 9 years ago

@PeterRao

统计和监控一般分为两大类:『业务统计』和『性能监控』

前者是业务指标,后者是技术指标

业务统计我们一般都是统计用户行为,点击、路径追踪、落地页、滚屏高度等,这部分应该没啥可说的,最多是可以实现一个小框架,然后约定页面上有某种特殊标签的元素,捕获其上事件,自动上报,这样就不用针对每个元素去自定义了,比如我们上约定元素如果有 data-stat 标记的元素被点击就要上报,上报的信息也都写在元素的属性中,这样开发过程就相对简化下来,在需要统计的地方给元素加上这些属性就好了。

技术指标就有很多内容,包括『T0时间』、『T1时间』、『首屏时间』、『可交互时间』,如果你是单页面应用,可能还会关注『页面切换时间』,我们团队在海外的项目,由于当地网络环境实在太差了,差不多是我们5、6年前的移动网络情况,所以我们还监控了页面的『到达率/折损率』,就是在页面的html代码的前中后三个地方分别打点,判断用户在哪个位置离开。最后就是『JS报错监控』,其实js报错的误报率挺高的(浏览器插件报错都可能被捕获到),千奇百怪,所以有点报错不用担心,主要是监控那些高频错误,js报错的收集就是window.onerror了,这些大家应该都做的差不多。另外还有一类日志,属于前端安全,主要是监控非本网站js脚本注入,可以看 这里

日志上报用 new Image().src=xxx ,不赘述。

此外,保留服务器访问日志(这个一般运维都会做),必要的时候可以通过写脚本分析访问日志来追查问题,这也是非常重要的问题分析和定位手段。

总的来说:

整套东西差不多就这些吧,可深入的细节还很多,总之大数据时代不搞搞小数据真的没法出去吹牛逼。

个人觉得统计与监控也是前端工程的重要组成部分,必须好好搞

small-carbon commented 9 years ago

@fouber UAE 代表什么东西

small-carbon commented 9 years ago

@fouber 每次构建的代码库包是补丁增量的形式,还是整个项目工程文件包呢?

fouber commented 9 years ago

@majianxiong

lenxeon commented 9 years ago

@fouber @nimojs 我想知道如何配置可以实现打包结果是 common:js/components/menus 而不是我下面的那样?两位谁知道在fis3里要配置什么?

define('js/components/menus', function(require, exports, module) {

  var $ = require('common:widget/jquery/jquery.js');

  exports.init = function() {
      $('.menu-ui ul li a').click(function(event) {
          var self = this;
          $('.menu-ui ul li a.active').removeClass('active');
          $(self).addClass('active');
          event.preventDefault();
      });
  };

});

目录结构

├── common-ui
│   ├── images
│   ├── js
│   │   ├── components
│   │   └── utils
│   ├── less
│   │   └── mixins
│   ├── lib
│   └── widget
├── lib
│   └── mod
│       ├── amd
│       ├── lib
│       └── test
│           ├── async_in_async
│           ├── asyncmore
│           ├── asynctest1
│           ├── circle
│           ├── complex
│           ├── cross
│           ├── manyasync
│           ├── multi
│           ├── pkg
│           ├── repeat
│           ├── ring
│           ├── ringcross
│           ├── self
│           └── single
├── mod-admin
└── mod-hr
lenxeon commented 9 years ago

@fouber @nimojs 最近看了fis3的一些例子,其中有一个问题我觉得始终没有找到想要的答案。

如怎么样字义一个components 例如一个button:如果是在react里我会有一个button.js的文件,render里会有这个button的dom结构,这个JS里我还会require一个button.less文件,这样别人使用的时候可以 var Button = require('path/button.js') 然后在需要的地方用

limichange commented 8 years ago

@fouber 关于map.json的使用方式我有些想法不知可不可行,想请教下的。将前端的部署独立开来,将map.json存在数据库当中,后端去读取map.json中的列表然后自己渲染。这样前端能独立部署升级,后端也不需要做多余的工作。版本出现问题的话,前后端可以各自回滚。

atian25 commented 8 years ago

这个方式当然可以,不过我们一般前后端分离的界限是,前端接管视图渲染层,通过API接口跟后端请求数据,这样map.json跟着前端就好了

limichange commented 8 years ago

@atian25 其实这样做是有一部分折中。因为index需要后端的特殊处理,所以index依旧需要后端处理。这样map.json是跟随着后端一起发布的,不是很灵活,所以产生了这样的想法。

Tronzo commented 8 years ago

先做个自我介绍,首先做前端 一极大个人爱好 和 实现自身价值。 前不久就再做 类似淘宝店铺装修项目,涉及点击穿透,用kissy框架去做的底层,用遮罩实现的 完全隔离操作层和展示层。 基本逻辑这些,有没有类似做过的 出来说一下 经验

atian25 commented 8 years ago

特殊处理指?node直接发个http跟后端交互不就OK?

myhirra commented 8 years ago

大家是如何处理大促之类的临时代码的?

举个例子,双十一了,运营/产品需要加一个特殊的逻辑。为了处理这个需求,在代码层面,我们肯定是需要加一个时间判断的,另外再加些这样的逻辑。但是,随着时间的推移,问题来了,这些代码已经没什么卵用了;而且随着这样的需求越多,这样『垃圾代码』也就会越来越多。这必然会影响整体的项目,项目会看起来越来越臃肿不堪。

我相信,不仅是前端会碰到,相信后端也会碰到,不知道有没有合理的工程化思路来解决这个问题?

ustbhuangyi commented 8 years ago

@myhirra 写好注释,写好TODO,很多编辑器如webstorm是可以check所有TODO的

aruis commented 8 years ago

@myhirra 一次性未必是临时,业务梳理得好,完全可以把这些一次性的工作抽象成一种常规业务,只是这种业务的发生频率较低罢了。

sssession commented 8 years ago

在尝试模块化,但是模块化后有一些问题。

  1. 例如百度统计、谷歌分析这类的代码算是一个模块吗,如何组织这类代码?
  2. css 模块化以后怎么解决容易命名冲突的问题?
  3. 例如 less 中有一些 mixin 或 css basic 样式怎么模块化?
jincdream commented 8 years ago

@sssession

zhoukekestar commented 8 years ago

你们不觉得组件化页面更好吗?每个组件中的css和js都对外进行隔离,确保里面不影响外面。组件容错要多,不管外部css和js怎么样(比如不会被是否有bootstrap影响到布局),都高度独立。一个组件由css、js、html组成(html是比js更好的粘合剂),高内聚,低耦合。我的这个项目就用到了类似的方法

feizhen commented 8 years ago

@zhoukekestar 组件化肯定是很好的,但也要考虑页面资源的问题,你把所有的组件都加载到一个页面,但是你的js,css文件合并和请求的策略是什么呢?如果都是分别加载的,那样对效率的影响还是挺大的

sssession commented 8 years ago

@zhoukekestar 赞同。组件是应该要独立,不论外部环境如何变化都应该表现一致。

但是对有些问题的处理还是比较困惑。 比如组件样式用到 rem 的时候需要依赖 html 的 font-size, 需要把这个控制权交给页面吗? 如果需要做到表现一致,那会有比较多基础的样式要在组件内部实现,这样不是会造成代码的冗余?

zhoukekestar commented 8 years ago

@feizhen js、css和html都并在一个html里面,所以,一个页面需要什么哪些组件,只要合并请求所需要的组件就行了,组件内部就包含了css和js,所以我说html是比js更好的粘合剂

a.html
<div data-register='a'>
<style>...</style>
<div>...</div>
<script>...</script>
</div>
b.html
<div data-register='a'>
<style>...</style>
<div>...</div>
<script>...</script>
</div>
demo.html
<link rel="import-webcom" href="./a.html,b.html">
<div>这里a和b组件的css,js和html都有了</div>
<div data-is='a'>a组件</div>
<div data-is='b'>b组件</div>

@sssession 你的问题非常好,确实是这样的,我在项目中的实践时也遇到了,多个项目公用一个组件,但有些用了bootstrap,有些没用,一种方式是用px,另外一种在组件内部定义一个字体大小,然后采用em,如果还解决不了,那就采用js,动态去设置咯,毕竟js还是蛮强大的。最后,也是比较推荐的一种方式,还是在所有项目中约定好html的font-size,这个由前端leader定好,然后执行就行了,也就一行代码的事。

feizhen commented 8 years ago

@zhoukekestar 我明白你的意思,这里的问题是,假设你的一个页面由4个组件组成,如果用你这种方法来组合的话,在http1.x的协议下,那么在加载这个页面的时候会向服务器发送多次的http请求,而且很多时候组件的css和js文件相对较小,如果不采取合适的合并和请求策略,那么在加载这个页面的时候会产生很多不必要的延迟

zhoukekestar commented 8 years ago

@feizhen 合并html组件就行了,不是很理解你的问题,本人理解能力比较差。。。只能重复解释一下了 ◔ ‸◔?

<script src='组件框架.js'></script>
<link rel="import-webcom" href="./组件1.html,组件2.html,组件3.html,组件4.html">
 <!-- 游览器不识别,该请求由框架异步发出,服务器收到请求后,将4个组件合并并返回  -->
<div>
使用组件
</div>

比如这个页面中使用了这些组件 qq 20160321134824

mycoin commented 8 years ago

百度统计、谷歌分析,loading 页面完全可以不走模块化~

好多好复杂·~~

zhoukekestar commented 8 years ago

天猫中将单图组件、上图下文这么细的都拆分成组件,模块与不模块化,组件与不组件化,还是要看怎么去拆分,怎么去看待拆分后的利与弊。 关于你说的问题,都是可以解决的。 https://github.com/tmallfe/tmallfe.github.io/issues/35

jincdream commented 8 years ago

@mycoin FIS3可以解决的。

我自己认为,组件只是业务逻辑的最终表现表现而已,其组件的相应js也只是结合自己的html调用了各js模块。

页面所需的组件,应该可以分析出所需的 CSS、JS、Tpl, 并且合并一次性加载~~

这个通过FIS3的配置和插件就能实现,也不难。

大多数组件应该是可以独立编译再运行的。

souse commented 8 years ago

@fouber 最近在研究fis3项目构建,用的是seaJs 不知道怎么引组件的css,直接在页面上引用 到时候会合并吗

web-basess commented 8 years ago

关于传统web与工程化

我想问下各位大神我从事前端也有几年了 不过都是1个人在摸索 ,工作中也是一个人独立完成项目。我现在想了解下前端工程化方面的东西。要从哪里下手呢。真的有点迷茫了。各种框架,工具,知识层出不穷。要怎么整理学习的思路呢 先学什么 后学什么 都要掌握哪些。

jincdream commented 8 years ago

@web-basess 我觉得吧,首先要先清楚你所在的公司在前端开发的过程中有什么问题,而这些问题是可以通过工具去解决的。 另外我安利下自己写的这个 fis3封装指南 ,应该会对你的思考有所帮助。~ https://github.com/jincdream/jincdream.github.io/issues/1

raymondmars commented 8 years ago

前端工程化的一个弊病是容易导致前端过分复杂化,不知道有没有同感?

Thyiad commented 8 years ago

不同意,你所谓的复杂化是有原因的,这些出来的工具和类库都是为了解决问题而出现的,你没有用过就不能下这样的断言

xxapp commented 8 years ago

@RobotJiang 个人认为是前端规模变大导致的前端工程化的产生,想象一下汽车工厂放弃工程化,全部改为手工生产,同时还要保持原来质量的产出,带来的麻烦会更多。复杂化是什么呢,操作员和工程师看到的东西可能还不一样。

jincdream commented 8 years ago

复杂是相对的,工程的构建之初当然需要相对复杂的架构设计,这样是为了让流水线生产的员工操作更简单。

在 2016年4月13日,上午11:33,Robot notifications@github.com 写道:

前端工程化的一个弊病是容易导致前端过分复杂化,不知道有没有同感?

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/fouber/blog/issues/8#issuecomment-209212130

raymondmars commented 8 years ago

@Thyiad 我从 grunt 再到 gulp ,还用了 webpack。框架的话最初用 backbone, 后来用 react, flux. 看我这个路线图,如果你一路下来,前端构建和开发都变的复杂了。当然也是前端更重了,业务结构大部分也转到前端了。然后用 react构建组件化开发,所以我说复杂化了,这个是个不争的事实。组件化后有利于分工合作,这个我也同意。但对于1,2个人的小团队来说,就过重了。

nimoc commented 8 years ago

@RobotJiang 认同『重』的事实
规范越来越多,就会越来越重。 1 ~ 2 人的小团队可以根据实际情况决定哪些规范和流程要哪些不需要。木有银弹


要根据项目情况选择合适的解决方案。但是有些事应该在开始就做的。

工具用 gulp fis react vue ng jquery 都无所谓,你不知道一个小型项目会不会慢慢发展成大型项目。

一个未经过前端工程化的小型项目如果演变成中型项目后代码冲突、文件过大等问题就及难解决。

raymondmars commented 8 years ago

@nimojs 严重同意。前期花费大量时间,还是值得的。不过后续员工的培训成本也会提高,除非大家已经有这方面的架构经验了。

Thyiad commented 8 years ago

@RobotJiang 是的啊,不是每个公司都辣么重视前端,都搞前后端分离的

ghost commented 8 years ago

是因为前端复杂了,才需要引入工程化。因果颠倒了。你写个中型网站,全站异步加载。尝试不用构件工具,不用工程化的思想去做。你就发现问题了。

在 2016年4月13日,上午11:33,Robot notifications@github.com 写道:

前端工程化的一个弊病是容易导致前端过分复杂化,不知道有没有同感?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/fouber/blog/issues/8#issuecomment-209212130

slowsay commented 8 years ago

哟,还可以这样,呵可

slowsay commented 8 years ago

大家讨论如何 优化,页面的加载速度吧

nimoc commented 8 years ago

@Thyiad 不需要彻底的前后端分离,比如在 MVC 中后端愿意将 View 层交给前端维护前端就可以在前端工程上做很多事。(让前端写后端模板,Controler 层还是交给后端写)这样 fouber 博客中讲到的的静态资源表就可以实现了。更深入一点还可以在html直接显示 css js ,一个页面一次HTTP请求显示所有内容。

当然后端不愿意让前端写模板也还是可以做很多事的。

Pines-Cheng commented 8 years ago

前后端分离还是挺重要的,但是又涉及到SEO问题,这个就比较坑了。