首页 文章 精选 留言 我的

精选列表

搜索[前端工程化],共10003篇文章
优秀的个人博客,低调大师

前端小报 - 201901 月刊

订阅 / 投稿:https://github.com/txd-team/monthly本期小编:x-cold (尹挚) 新闻快报 重磅消息:Github 宣布私有仓库免费,同期还上线了星标话题(topics) 的功能 2019 年伊始,GitHub 正式宣布开放无限制创建私有存储库,并开始提供统一的企业版 GitHub 服务,微软正在开始加速 toB 企业服务的布局。开发者们一片叫好声,可谓年度最佳的程序员福利了。 软件技术 B2B 公司Idera.inc收购 Travis CI Travis CI 将结合 Idera 公司其本身的数据库 / 开发者 / 测试等工具发挥更大的商业优势。不过使用免费版的社区同学也不用紧张,Travis CI 依然保证对开源软件免费的策略,并且其开源证书不会修改 (MIT),更多可以参考详细的官方公告。 需

优秀的个人博客,低调大师

前端异常监控神器

有时候,看到用户的反馈,我们往往会一脸茫然,因为反馈的信息太少了。 比如有用户反馈登录不了。为了解这个问题,一般的流程是这样的:首先试试自己能不能登录网站,发现没问题;然后查看后台日志,发现最近没有登录接口相关的报错;最后根据用户反馈的时间,去后台查日志记录。结果日志记录没有错误信息。 那这个问题没法解决了!除非找出用户的联系信息,和他去聊聊这个bug。 mengbi.jpg 这样的情况很多,有时候及时有报错信息,还是一脸蒙逼,不知道为啥呢。 是不是很蛋疼? 不过这个问题已经可以很好滴解决啦!Fundebug最近上线了一个新的大功能,叫做场景重现。其实直观理解就是加了个视频录制,把用户出错前的行为习惯可视化的录制,然后绑定到对应的错误上。通过观看场景重现,可以直观的去理解用户是如何触发错误的。如下面所示: eleme_full.gif 是不是很惊艳!不仅可以看到报错相关信息,还可以看到用户的操作视频。 实例测试 为了验证一下是否真的这么牛逼,我弄了一个简单的网站来测试一下。 为了跟大家演示,我在Github上找了一个TodoMVC项目,这样可以快速跑起来。 下载代码git clone https://github.com/isjingzhi/TodoMVC.git 安装依赖npm install 运行npm run start 项目成功跑起来了,请看下图: todomvc1.png 接下里我需要将Fundebug的JavaScript监控插件接入,首先在Fundebug网站创建一个Vue的监控项目。 create.png 然后接入代码,接入部分很多代码,只能截图一部分,不过还是比较简单的,你只需要复制黏贴就可以了。 integrate.png 首先在index.html中接入script脚本: integrate1.png 然后,在添加errorHandler代码: integrate2.png 最后,我们再假装造个错试试,我在app.js的clearAlldone函数中,故意把this改为that: createerror.png 来我们试试Fundebug能抓到怎样的错误。 我随意添加任务,然后又删除任务,最后点击右下角的Clear completed,然后就收到报错了。 error.png 基本的报错堆栈信息都有 ReferenceError Uncaught ReferenceError: that is not defined at Vue.clearAlldone (http://localhost:3000/js/app.js:120:19) at invoker (http://localhost:3000/node_modules/vue/dist/vue.js:2029:18) at HTMLButtonElement.fn._withTask.fn._withTask (http://localhost:3000/node_modules/vue/dist/vue.js:1828:18) 现在我们来看看场景重现的效果: redo.png 鉴于是一段"视频“,我再单独放出来: todomvc.gif 通过这段视频,就可以很形象去理解用户的操作流程!不得不说是一大神器! 参考 TodoMVC on Github Fundebug JavaScript监控插件

优秀的个人博客,低调大师

Web前端 — Bootstrap(6)

Bootstrap本次知识点 1.按钮组件 2.输入框 1. 按钮组件 (1)基本按钮组件 <div class="btn-group"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> (2)按钮工具栏 <div class="btn-toolbar"> <div class="btn-group"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> <div class="btn-group"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> <div class="btn-group"> <button class="btn btn-default">更多</button> </div> </div> (3)按钮的大小 <div class="btn-group btn-group-lg"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> <div class="btn-group btn-group-sm"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> <div class="btn-group btn-group-xs"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <button class="btn btn-default">right</button> </div> (4)嵌套 <div class="btn-group"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <div class="btn-group"> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">按钮 <span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">1</a></li> <li><a href="">2</a></li> <li><a href="">3</a></li> </ul> </div> </div> (5)垂直的按钮组 <div class="btn-group-vertical"> <button class="btn btn-default">left</button> <button class="btn btn-default">middle</button> <div class="btn-group"> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">按钮 <span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">1</a></li> <li><a href="">2</a></li> <li><a href="">3</a></li> </ul> </div> </div> (6)两端对齐排列的按钮组 <div class="btn-group btn-group-justified"> <div class="btn-group"> <button class="btn btn-default">left</button> </div> <div class="btn-group"> <button class="btn btn-default">middle</button> </div> <div class="btn-group"> <button class="btn btn-default">right</button> </div> </div> <div class="btn-group btn-group-justified"> <!--<div class="btn-group">--> 为了浏览器兼容问题使用btn-group包裹 <a href="" class="btn btn-default">left</a> <!--</div>--> <!--<div class="btn-group">--> <a href="" class="btn btn-default">middle</a> <!--</div>--> <!--<div class="btn-group">--> <a href="" class="btn btn-default">right</a> <!--</div>--> </div> (7)按钮式下拉菜单 <1>单按钮下拉菜单 <div class="btn-group"> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">Default <span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">html</a></li> <li><a href="">javascript</a></li> <li><a href="">jQuery</a></li> </ul> </div> <2>分裂式按钮下拉菜单 <div class="btn-group"> <button class="btn btn-default">Default</button> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">html</a></li> <li><a href="">javascript</a></li> <li><a href="">jQuery</a></li> </ul> </div> <3>按钮下拉菜单的大小 <div class="btn-group"> <button class="btn btn-default btn-lg dropdown-toggle" data-toggle="dropdown">Default <span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">html</a></li> <li><a href="">javascript</a></li> <li><a href="">jQuery</a></li> </ul> </div> <4>向上弹出式菜单 <div class="btn-group dropup"> <button class="btn btn-default btn-lg dropdown-toggle" data-toggle="dropdown">Default <span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">html</a></li> <li><a href="">javascript</a></li> <li><a href="">jQuery</a></li> </ul> </div> 2.输入框 (1)基本的输入框组 <form action=""> <div class="input-group"> <span class="input-group-addon">@</span> <input type="text" class="form-control"/> </div> <div class="input-group"> <input type="text" class="form-control"/> <span class="input-group-addon">.00</span> </div> <div class="input-group"> <span class="input-group-addon">$</span> <input type="text" class="form-control"/> <span class="input-group-addon">.00</span> </div> </form> (2)输入框组的大小 <form action=""> <div class="input-group input-group-lg"> <span class="input-group-addon">@</span> <input type="text" class="form-control"/> </div> </form> (3)复选框和单选框的插件 <form action=""> <div class="row"> <div class="col-md-6"> <div class="input-group"> <span class="input-group-addon"> <input type="checkbox"/> </span> <input type="text" class="form-control"/> </div> </div> </div> </form> (4)按钮插件 <form action=""> <div class="row"> <div class="col-md-6"> <div class="input-group"> <span class="input-group-btn"> <button class="btn btn-default">Go</button> </span> <input class="form-control" type="text"/> </div> </div> </div> </form> (5)按钮式下拉菜单 <form action=""> <div class="row"> <div class="col-md-6"> <div class="input-group"> <div class="input-group-btn"> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">dropdown<span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="">资讯</a></li> <li><a href="">新闻</a></li> <li><a href="">关于</a></li> </ul> </div> <input class="form-control" type="text"/> </div> </div> </div> </form> (6)分列式按钮下拉菜单 <form action=""> <div class="row"> <div class="col-md-6"> <div class="input-group"> <div class="input-group-btn"> <button class="btn btn-default">dropdown</button> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown"> <span class="caret"></span> </button> <ul class="dropdown-menu"> <li><a href="">资讯</a></li> <li><a href="">新闻</a></li> <li><a href="">关于</a></li> </ul> </div> <input class="form-control" type="text"/> </div> </div> </div> </form> 作者:Roger_CoderLife 链接:https://blog.csdn.net/Roger_CoderLife/article/details/80451109 本文为Roger_CoderLife的原创文章,著作权归作者所有,转载请注明原文出处,欢迎转载!

优秀的个人博客,低调大师

前端工程架构探讨

回忆一下我们在工程开发中对目录结构的定义,一般分为两种,单页面多模块,多页面多模块。在单页面多模块的工程结构里,我们会考虑模块的复用性,比如:如何将公共的东西(样式、函数等)提取出来方便其他模块复用。在多页面多模块的场景中,也是一样,不过除了把全局共用的样式和方法提取到公共目录外,我们还会将多个地方都会用到的模块作为通用模块处理。 一、通常开发模式的问题探讨 下图是一个单页面多模块的工程目录结构图: . ├── Gruntfile.js ├── package.json ├── build └── src ├── base │ ├── base.sass │ └── global.js ├── mods │ ├── preference │ │ ├── index.js │ │ ├── index.sass │ │ └── index.xtpl.html │ ├── promo │ ├── qr │ └── response └── index.js 我们把源码放在 src 文件夹里面,公共的文件(iconfont 、sprite 图片、CSS 和 JS 等)放到 base 目录下,页面中的每个模块都会在 mods 下新建一个文件夹,使用index.js来管理模块的渲染。 // index.js define(function(require){ var Lazyload = require('lazyload'); var Preference = require('./mods/preference/index'); var Qr = require('./mods/qr/index'); var Promo = require('./mods/promo/index'); var Response = require('./mods/response/index'); new Response(); if(xxx){ new Promo(); } Lazyload(function(){ new Qr(); new Preference(); }); }); 这样的工程结构是十分通用,结构也比较清晰的,不过在模块的管理上,这里会存在两个问题: AB模块存在较多的共用代码,我们有两种方式处理,一是将公共部分提取出来放到 base 目录下,二是 B 模块直接根据相对路径引用 A 模块。一旦业务上有需求,说 A 模块要下线,那下线之后,第一种方案放置在 base 目录下的代码就不合理了,第二种方案中 B 模块就不能用了,需要将 A 模块的东西部分迁移到 B 模块。 问题 1 的逆过程:线上目前存在 A 模块,业务上需求需要添加跟 A 模块相似的 B 模块,如果想直接复用 A 模块的代码,一种方式是更小颗粒地分拆 A 模块,然后 B 使用相对路径引用 A,另一种方式是将 A 的共用代码提取出来放到 base 下。两种处理方式都有一定的工作量,而且还会出现问题 1 提到的问题。 其实说到底还是模块的耦合度过高,只要模块之间存在交集,一个模块的改动就可能会影响到其他模块。多人开发中,这里还存在其他方面的问题: 并不是每个开发者对接手的项目都有一个全局的把控,下线一个模块时,会不太敢删除 base 目录下跟该模块相关的东西,甚至都不太敢删除这个模块,只是在index.js中注释了这个模块的初始化。日积月累,冗余代码便会渗入到项目的各个地方… 修改一个模块需要编译打包所有的代码(部分情况下需要编译,比如存在离线模板,将 html 模块编译成 js),这样的调试效率十分低下,而且这个模块出错,就可能造成整个程序的崩溃。 代码历史版本管理的颗粒度不够,比如我修改了 A、B、C 三个模块,依次上线了三次,现在要回滚修改 A 的操作,如何处理?如果 ABC 三个模块都能够利用代码管理工具管理代码,那回滚就方便多了。 二、模块化处理 去耦合的方式就是让模块之间共用的东西减少,当模块之间不存在共用内容时,耦合度基本就是零了。 . ├── init.js ├── build └── src ├── preference <git> │ ├── index.js │ ├── index.sass │ └── index.xtpl.html ├── promo <git> ├── qr <git> └── response <git> 如上图所示,与之前的结构相比,已经少了很多东西: index.js初始化模块的东西不见了,多了一个init.js base目录不见了 每个模块都变成了一个 git 仓库 1. 脚本的初始化 先看看init.js在干啥: // init.js var $mods = $("[tb-mods]"); $mods.each(functon($mod){ if($mod.attr("finish") !== FINISH_TAG) { $mod.attr("finish", FINISH_TAG); // 需要懒加载便懒加载 if($mod.attr("lazyload")){ Lazyload($mod); return; } // 否则直接初始化 S.use($mod.attr("path"), function(S, Mod){ new Mod($mod); }); } }); function Lazyload(){ // code here.. } init.js不再对模块进行精确初始化,文档从上往下遍历,找到模块便直接初始化,如果需要懒加载就加入到懒加载队列,开发者不用理会页面上有多少模块,更不用理会各个模块叫做什么名字。 index.js中 require 很多很多模块,每次添加一个模块或者删除模块都要改动这个文件,而是用init.js不会存在这个问题。 2. 模块的版本控制 <!-- index.xtpl.html --> <div tb-mods lazyload path="tb/promo/1.0.0"></div> <div tb-mods lazyload path="tb/qr/2.0.0"></div> <div tb-mods lazyload path="tb/preference/2.2.1"></div> <div tb-mods path="tb/response/3.0.2"></div> 页面上的 DOM 就是标识,存在 DOM 属性标识就执行这个标识对应的脚本,执行顺序就是 DOM 的摆放顺序。 每个模块代码都使用单个 git 仓库管理,这样能够更好地追踪单个模块的修改记录和版本,也可以解决上面提出的问题(依次修改 ABC 模块,并上线了三次,如果需要回滚 A 模块,则 BC 模块的修改也要跟着滚回去)。 3. ABTest 需求 修改一个模块后,只需要修改他在 DOM 的版本号即可上线。如果遇到 ABTest 的需求,那也十分好办了: <!-- index.xtpl.html --> {{#if condition}} <div tb-mods lazyload path="tb/promo/1.0.0"></div> {{else}} <div tb-mods path="tb/promo/2.0.0"></div> {{/if}} <div tb-mods lazyload path="tb/qr/2.0.0"></div> <div tb-mods path="tb/response/3.0.2"></div> tb/promo目前有两个版本,1.0.0 和 2.0.0,需求是两个版本以 50% 的概率出现,直接在index.xtpl.html做如上修改,程序是十分清晰的。 4. 公共文件的处理 那么,公共的代码跑哪里去了?其实我们并不希望有公共的代码产生,上一节中已经提出了耦合给我们带来的维护问题,但是一个项目中必然会有大量可复用的东西,尤其是当页面出现很多相似模块的时候。 1)模块的复用 一个模块的渲染,需要两样东西,渲染壳子(模板) + 数据,渲染的壳子可能是一样的,只是数据源不一样,很多情况下我们可以复用一套 CSS 和 JS 代码,通过下面的方式: <!-- index.xtpl.html --> <div tb-mods lazyload path="tb/promo/1.0.0" source="data/st/json/v2"></div> <div tb-mods lazyload path="tb/promo/1.0.0" source="data/wt/json/v1"></div> 在两个相似模块中,我们使用的是同一套 js -tb/promo/1.0.0,但是使用了两个不同的数据源data/st/json/v2,data/wt/json/v1。 // init.js $mods.each(functon($mod){ if($mod.attr("finish") !== FINISH_TAG) { //... S.use($mod.attr("path"), function(S, Mod){ // 将数据源传入 new Mod($mod, $mod.attr("source")); }); //... } }); 在初始化脚本中,我们将模块需要用到的数据源传入到模块初始化程序中,这样页面就成功的复用了tb/promo/1.0.0的资源。 2)CSS 的复用问题使用 less 的 mixin 处理 @a: red; @b: white; .s1(){ color: @a; background: @b; } .s2 { color: @a; background: @b; } LESS 是 CSS 的预处理语言,上面的代码打包之后,.s1是不存在的,只有.s2会被打包出来,但是两者都可以 mixin 到其他类中: .s { .s1; .s2; } 利用这个特点,我们可以把共用的 css 都包装成类似.s1的 less 代码,模块中需要的时候就 mixin,不需要的话,放在那里也没关系,不会造成代码冗余。 3)JavaScript 的代码复用问题 页面级别的 JS 代码其实并不多,比如我们平时用的比较频繁的有 Slide、Lazyload、Tab、Storage 等,但这些东西都是以组件的形式引入到页面中。仔细想一想,JS 中哪些代码是需要页面共用的?相对整个项目的文件大小,共用的部分又有多少? 我们使用的基础库方法并不全面,比如:没有对 URL 解析的unparam方法,而这个方法用的也比较多,希望放到公共部分中去。回头想想,这样的小函数实现起来有啥难度么,三四行代码就能写出来的东西,建议放到组件内部搞定。这会造成一定的代码冗余,但是带来的解耦收益与费力写几行代码的成本相比,这完全是可以接受的。 页面共用的统计代码、错误收集代码、数据缓存方案、组件通讯代码等,这些量比较大、使用颇为频繁的内容,可以封装成组件,以组件形式引入进来。 这里还需要很多思考… 5. 模块之间的通讯 模块之间的通讯最让人纠结的是,A 模块想跟 B 模块说话,但是 B 模块还没有初始化出来。所以我们需要引入一个中间人 S,每个模块初始化成功之后都去问一问 S,有没有人给我留言。 // B 给 A 留言,如果 A 存在,则直接将 msg 发给 A // 如果不存在则送入 S 的消息队列 S.tell("A", { from : "B", msg: {} }); // A 模块初始化的时候,获取其他模块的留言 S.getMessage("A", function(msg){ // dosomething... }); 三、小结 还有很多东西不在主题的讨论范围内,就不一一列举出来了。 项目开发参与的人越多,代码就越难维护,约束只是一时的,编程方式、编码格式等的约束并不能从根本上解决问题,一旦约束的点未覆盖,结构就会开始散乱,最后必然又会迎来一次整体的重构。 方法和结果不能改变习惯,所以我们应该从模式出发。 本文转自Barret Lee博客园博客,原文链接:http://www.cnblogs.com/hustskyking/p/fe-project.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

OpenClaw 入门指南:核心原理、工程化接入与避坑实践

目录一、OpenClaw 到底是什么二、新手如何快速上手 OpenClaw三、使用 OpenClaw 必须避开的几个坑四、几个 prompt 实战示例五、Python 实战:通过代理层稳定调用 OpenClaw API六、代理层在 AI 工程中的定位一、OpenClaw 到底是什么OpenClaw 是一套面向开发者的对话式人工智能框架,底层建立在 Transformer 这种自回归生成架构之上。与仅具备"next-token prediction"能力的朴素模型不同,它在工程上把语义理解、上下文记忆、外部工具调用(function calling)三件事整合进了统一的推理管线。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册