百度-APP产品研发-秋招 · 第 1 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 面试时间: 60分钟 本轮共 21 道题。答案默认折叠,便于先自行作答。 1. 讲一下你在官网开发中的主要职责,开发的模块以及你觉的比较亮点的地方 题目要点 如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”,一般可以从以下几个角度来回答,既展示你的全局把控能力,又体现你在某些点上有深度。 参考答案 如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”,一般可以从以下几个角度来回答,既展示你的全局把控能力,又体现你在某些点上有深度。 下面是一个参考思路: 1. 主要职责 官网整体架构搭建:根据业务和设计稿,使用 React/Vue + Vite/Next.js/Nuxt.js 等技术栈完成整体框架搭建,包括路由、状态管理、多语言支持等。 公共模块封装:抽象公共组件(如导航栏、页脚、轮播、富文本渲染、内容卡片等),提高复用率,减少重复开发。 性能优化:处理首屏加载速度、资源拆分、图片懒加载、SSR/SSG、SEO 优化。 协作沟通:与产品、UI、后端保持沟通,保证页面上线节奏和质量。 2. 负责的模块(可根据实际情况举例) 首页:承担品牌形象展示,涉及 banner 动效、动态数据展示、视频播放等。 产品/解决方案页:结合后端接口,展示不同产品模块,支持筛选、搜索、动态路由。 活动/新闻动态页:接入 CMS(如 Strapi、Sanity、WordPress 等),支持运营人员通过后台直接发布。 多语言切换模块:基于 i18n 实现官网多语言,支持自动识别浏览器语言,静态资源跟随切换。 SEO 优化模块:处理 meta 信息、OG 标签、站点地图、robots.txt,提升搜索引擎收录效果。 3. 亮点/难点突破 性能优化亮点 利用 SSR/SSG(Next.js/Nuxt.js)提升首屏渲染速度,Lighthouse 分数提升到 90+。 使用图片 CDN + WebP 格式,首页加载时间缩短 30%。 按需加载组件、拆分 bundle,减少首次请求体积。 可配置化思路 引入 CMS 系统,实现官网内容可配置,避免频繁改代码上线,运营可直接维护。 封装通用“模块化组件”,如 Banner、富文本、图文组合,做到拖拽/配置式渲染。 前端体验优化 首页/产品页引入 动效(基于 Lottie 或 GSAP),提升视觉冲击力。 交互细节(滚动吸附、视差动画、过渡效果)增强用户沉浸感。 工程化实践 ...

August 20, 2025

百度-APP产品研发-秋招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 1 轮 → 本轮共 15 道题。答案默认折叠,便于先自行作答。 1. 前端实现动画有哪些方式? 题库原题:前端实现动画有哪些方式? 题目要点 前端开发中,实现动画的方法多种多样,每种方法都有其适用场景和优缺点。以下是一些常见的实现方式: CSS 动画: 使用 @keyframes 和 animation 属性定义动画。 优点:易于实现,性能好,易于维护。 缺点:功能相对简单,难以实现复杂的交互动画。 CSS 过渡(Transitions): 使用 transition 属性在状态变化时实现平滑过渡。 优点:简单易用,性能优秀。 缺点:只能用于状态变化的过渡,不适合复杂动画。 JavaScript 动画: 使用 JavaScript 直接操作 DOM 元素的样式属性实现动画。 优点:灵活性高,可以控制动画的每一个细节。 缺点:可能影响性能,需要更多的代码实现。 Web Animations API: 使用 Element.animate() 方法实现动画。 优点:提供更丰富的动画控制和更一致的跨浏览器支持。 缺点:兼容性不如 CSS 动画。 SVG 动画: 使用 SVG 元素和 SMIL(Synchronized Multimedia Integration Language)或 CSS 动画实现动画。 优点:适合矢量图形动画,易于集成。 缺点:浏览器支持和性能可能不如 CSS 动画。 Canvas: 使用 HTML <canvas> 元素和 JavaScript 绘制动画。 优点:适合复杂的图形和游戏动画。 缺点:实现复杂,需要手动管理每一帧的绘制。 CSS 3D 变换: ...

August 19, 2025

状态管理工程化

状态管理是一个前端界老生常谈的话题了,所有前端框架的发展历程中都离不开状态管理的迭代与更替,对于react来说呢,整个状态管理的发展也随着react架构的变更和新特性的加入而不停的做调整,作为一个一起伴随react成长了快5年的开发者,经历过reflux、redux、mobx,以及其他redux衍生方案dva、mirror、rematch等等后,我觉得它们都不是我想要的状态管理的终极形态,所以为了打造一个和react结合得最优雅、使用起来最简单、运行起来最高效的状态管理方案,踏上了追梦旅途。 为何需要状态管理 为何需要在前端引用里引入状态管理,基本上大家都达成了共识,在此我总结为3点: 随着应用的规模越来越大,功能越来越复杂,组件的抽象粒度会越来越细,在视图中组合起来后层级也会越来越深,能够方便的跨组件共享状态成为迫切的需求。 状态也需要按模块切分,状态的变更逻辑背后其实就是我们的业务逻辑,将其抽离出来能够彻底解耦ui和业务,有利于逻辑复用,以及持续的维护和迭代。 状态如果能够被集中的管理起来,并合理的派发有利于组件按需更新,缩小渲染范围,从而提高渲染性能 已有状态管理方案现状 redux 遵循react不可变思路的状态管理方案,无论从git的star排名还是社区的繁荣度,首推的一定是redux这个react界状态管理一哥,约束使用唯一路径reducer纯函数去修改store的数据,从而达到整个应用的状态流转清晰、可追溯。 image.png mbox 遵循响应式的后期之秀mbox,提出了computed、reaction的概念,其官方的口号就是任何可以从应用程序状态派生的内容都应该派生出来,通过将原始的普通json对象转变为可观察对象,我们可以直接修改状态,mbox会自动驱动ui渲染更新,因其响应式的理念和vue很相近,在react里搭配mobx-react使用后,很多人戏称mobx是一个将react变成了类vue开发体验的状态管理方案。 image.png 当然因为mbox操作数据很方便,不满足大型应用里对状态流转路径清晰可追溯的诉求,为了约束用户的更新行为,配套出了一个mobx-state-tree,总而言之,mobx成为了响应式的代表。 其他 剩下的状态管理方案,主要有3类。 一类是不满足redux代码冗余啰嗦,接口不够友好等缺点,进而在redux之上做2次封装,典型的代表国外的有如rematch,国内有如dva、mirror等,我将它们称为redux衍生的家族作品,或者是解读了redux源码,整合自己的思路重新设计一个库,如final-state、retalk、hydux等,我将它们称为类redux作品。 一类是走响应式道路的方案,和mobx一样,劫持普通状态对象转变为可观察对象,如dob,我将它们称为类mobx作品。 剩下的就是利用react context api或者最新的hook特性,主打轻量,上手简单,概念少的方案,如unstated-next,reactn、smox、react-model等。 我心中的理想方案 上述相关的各种方案,都各自在一定程度上能满足我们的需求,但是对于追求完美的水瓶座程序猿,我觉得它们终究都不是我理想的方案,它们或小而美、或大而全,但还是不够强,不够友好,所以决定开始自研状态管理方案。 我知道小和 美、全、强本身是相冲突的,我能接受一定量的大,gzip后10kb到20kb都是我接受的范围,在此基础上,去逐步地实现美、全、强,以便达到以下目的,从而体现出和现有状态管理框架的差异性、优越性。 让新手使用的时候,无需了解新的特性api,无感知状态管理的存在,使其遁于无形之中,仅按照react的思路组织代码,就能享受到状态管理带来的福利。 让老手可以结合对状态管理的已有认知来使用新提供的特性api,还原各种社区公认的最佳实践,同时还能向上继续探索和提炼,挖掘状态管理带来的更多收益。 在react有了hook特性之后,让class组件和function组件都能够享有一致的思路、一致的api接入状态管理,不产生割裂感。 在保持以上3点的基础上,让用户能够使用更精简且更符合思维直觉的组织方式书写代码,同时还能够获得巨大的性能提升收益。 为了达成以上目标,立项concent,将其定义为一个可预测、零入侵、渐进式、高性能的增强型状态管理方案,期待能把他打磨成为一个真真实实让用户用起来感觉到美丽、全面、强大的框架。 说人话就是:理解起来够简单、代码写起来够优雅、工程架构起来够健壮、性能用起来够卓越…… ^_^ concent.png 可预测 react是一个基于pull based来做变化侦测的ui框架,对于用户来说,需要显式的调用setState来让react感知到状态变化,所以concent遵循react经典的不可变原则来体现可预测,不使用劫持对象将转变为可观察对象的方式来感知状态变化(要不然又成为了一个类mobx……), 也不使用时全局pub&sub的模式来驱动相关视图更新,同时还要配置各种reselect、redux-saga等中间件来解决计算缓存、异步action等等问题(如果这样,岂不是又迈向了一个redux全家桶轮子的不归路….. ) 吐槽一下:redux粗放的订阅粒度在组件越来越多,状态越来越复杂的时候,经常因为组件订阅了不需要的数据而造成冗余更新,而且各种手写mapXXXToYYY很烦啊有木有啊有木有,伤不起啊伤不起…… 零入侵 上面提到了期望新手仅按照react的思路组织代码,就能够享受到状态管理带来的福利,所以必然只能在setState之上做文章,其实我们可以把setState当做一个下达渲染指令重要入口(除此之外,还有forceUpdate)。 setState,下达更新指令 仔细看看上图,有没有发现有什么描述不太准确的地方,我们看看官方的setState函数签名描述: 代码语言:txt AI代码解释 setState<K extends keyof S>( state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null), callback?: () => void ): void; 通过签名描述,我们可以看出传递给setState的是一个部分状态(片段状态),实际上我们在调用setState也是经常这么做的,修改了谁就传递对应的stateKey和值。 ...

August 7, 2025

单页面架构

传统的多页面应用构建方式: 纯服务端渲染,前后端不分离,使用jsp,jade,’ejs’,’tempalte’等技术在后台先拼接成对应的HTML结构,然后转换成字符串,在每个对应的路由返回对应的数据(文件)即可 Jade模版服务端渲染,代码实现: const express= require('express') const app =express() const jade = require('jade') const result = *** const url path = *** const html = jade.renderFile(url, { data: result, urlPath })//传入数据给模板引擎 app.get('/',(req,res)=>{ res.send(html)//直接吐渲染好的`html`文件拼接成字符串返回给客户端 }) //RestFul接口 app.listen(3000,err=>{ //do something }) 使用jQuery等传统库绘制的前端页面 传统前后端不分离,服务端渲染的优缺点: 优点: SEO友好,因为返回给前端的是渲染好的HTML结构,里面的内容都可以被爬虫抓取到。 对于一些应用性能等要求不高的项目,比如某个公司的静态网页,内容很少的情况下,直接一把梭就好,不用再搭建工程化的环境等 对于后端程序员(全干工程师)来说,不用去特意学习前端框架,公司也不用特意去招聘前端 兼容性好,传统服务端渲染多页面应用吐出来的都是字符串,HTML结构 缺点: 如果项目很大,不利于维护,据我所知,目前很多云计算公司,还有不少都是使用非单页面应用,例如一个几十万行的项目是用jQuery写的,如果注释和文档不是非常齐全,那么真的会无从下手 性能和用户体验,不能跟单页面应用相比 后期迭代,升级空间不大,目前大部分写得比较好的库,都建立vue,react等框架基础上,他们都有一套自己的运行机制,有自己的生命周期,并且不像传统的应用,还加上了一层虚拟DOM以及diff算法 现在类似Ant-Design-pro这样的开箱即用的库已经很多,单页面应用的学习和开发成本已经很低很低,如果还在使用传统的技术去开发新的应用,对于开发人员多内心来说也是一种折磨。 这里并不是说多页面应用不好,只能说各有各自的好,单页面应用如果通过大量的极致优化手段,是可以从不少方面跟原生一拼。 目前的单页面应用: 只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次,常用于PC端官网、购物等网站 其实只有一个空的DIV标签,其他都是js动态生态的内容 单页面应用实现步骤: 代码实现: 首先是一个静态模板文件 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="root"></div> </body> <script> </script> </html> 在vue react框架的入口文件中指定对应的渲染元素: import React from 'react; import ReactDOM from 'react-dom'; ReactDOM.render( <App/>, document.querySelector("#root") ) 引入react-router或者 react-router-dom,dva等路由跳转的库 配置路由跳转 <HashRouter>//这里使用HashRouter <ErrorBoundary>//React错误边界 <Switch> <Route path="/login" component={Login} /> <Route path="/home" component={Home} /> <Route path="/" component={NotFound} />//404路由或者重定向都可以 </Switch> </ErrorBoundary> </HashRouter> 单页面应用所谓路由跳转,其实最终结果就是: 浏览器的url地址发生变化,但是其实并没有发送请求,也没有刷新整个页面 根据我们配置的路由信息,每次点击切换路由,会切换到不同的组件显示,类似于选项卡功能的实现,但是同时url地址栏会变化 分为HashRouter和BrowserRouter两种模式 自己实现一个粗略的路由跳转: 自己实现传统的Hash模式跳转: hash 就是指 url 后的 # 号以及后面的字符。例如www.baidu.com/#segmentfault,那么#segmentfault就是hash值 ...

August 7, 2025

前端组件化开发

背景 不知道你有没有遇到过以下场景: 页面逻辑越来越多,代码越来越庞大,写到后面难以 hold 住所有逻辑,很容易牵一发而动全身. 你负责的页面好好的突然出现问题,查到最后是别人代码影响. 同样的逻辑在多个地方重复书写,每次一改要改一批文件 随着前端项目复杂度的急剧增加, 上面列出的几种场景就是传统开发中会出现的问题. 也是前端组件化出现的原因. 项目复杂度增加, 一个页面一个文件需要处理的内容过多. 重复性劳动多, 效率低 质量差, 不可控 组件化初探 正是由于出现了这样的问题, 为了在越来越复杂的前端项目中提高开发效率和保证开发质量, 各路大神们开始通过各种方式来尝试解决问题. 曾经非常火的 jQuery 就基于自己建立了 jQuery 插件机制. 你可以将一些常用逻辑进行封装变成 jQuery 插件, 还可以将插件开源进行共享. 比如纯手写会吐血的日期时间选择器,轮播, 多级菜单等等. 你可以在这里浏览更多jQuery插件. jQuery 插件的用法通常是: $(".select").pluginName(config) 除了 jQuery 插件模式, 还有一种常见模式是对象模式. 这种模式现在仍然有很多优秀的库在被我们直接或者间接使用. 比如: swiper 对象模式的写法: <!-- Slider main container --> <div class="swiper-container"> <!-- Additional required wrapper --> <div class="swiper-wrapper"> <!-- Slides --> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> ... </div> </div> <script src="path/to/swiper.min.js"></script> <script> var mySwiper = new Swiper ('.swiper-container', { direction: 'vertical', loop: true, }) </script> 对象模式通过配置创建对象, 通常创建对象的参数中有一项是元素/元素选择器, 通过js代码将逻辑与这个元素紧密绑定. ...

August 7, 2025

前端性能监控

大纲 我们会从以下三个方向来讲解埋点与监控的知识: 什么是埋点?什么是监控? JS 中实现监控的核心方案 写一个“相对”完整的监控实例 一、什么是埋点?什么是监控? 在日常沟通中,我们经常会把【埋点】和【监控】放到一起说,但是它们在本质上是有一定的区别的: 1. 埋点 埋点主要用于收集用户行为数据。在日常开发中,我们会通过 在前端代码中插入代码或脚本的方式 来实现埋点功能。 埋点的主要作用就是:捕获特定用户行为(如点击、浏览、提交表单、页面跳转等)以及关键业务数据(如下单金额、商品类别等) 在日常开发中,埋点的实现方案大致可以分为以下三大类: 手动埋点:在代码中手动加入记录代码来捕获特定事件。 自动埋点:利用 DOM 事件代理等技术来捕获页面上所有事件,从而减少手动配置。 可视化埋点:通过工具界面标记需要采集的元素和事件,可以不用手写代码。 2. 监控 而监控则主要关注 系统的性能和稳定性。在日常开发中,我们会通过 采集页面加载时间、资源请求、错误日志等数据 的方式来实现前端监控。 监控的主要作用就是:及时发现并定位页面性能瓶颈或代码异常,目的是为了保障系统不出 bug 在日常开发中,监控一般需要完成以下三大部分: 性能监控:如:首屏加载时间、页面交互耗时、资源加载耗时等。 错误监控:捕获 JavaScript 错误、网络请求失败、资源加载异常等。 用户体验监控:收集白屏、卡顿等影响用户体验的问题等。 区别总结 维度 前端埋点 前端监控 目标 捕获用户行为数据 监控系统性能、错误、稳定性 数据类型 用户点击、表单提交、页面跳转等 页面加载时间、错误日志、卡顿情况等 实现方式 手动埋点、自动埋点、可视化埋点 错误捕获、性能指标采集 核心关注点 用户行为、业务数据 系统Bug、性能优化 二、JS 中实现监控的核心方案 根据上面所说,我们知道埋点和监控的目的存在不同,但是它们的思路确是有很多一致性的,其核心都是:获取关键的数据,发送(上报)给服务端,依据数据来解决其不同的目的。 所以,无论是埋点也好,还是监控也罢,我们都需要 获取关键位置数据。 1. 跟踪用户事件(点击、滚动等) 定义通用跟踪函数(后续事件会通过该函数完成上报):trackEvent 函数接收事件类型和事件详情,并上报到服务端。 // 用于记录或发送跟踪数据到服务器的函数 function trackEvent(eventType, details) { console.log(`Event: ${eventType}`, details); // 在控制台打印事件类型和详情 // 上报到服务端。 fetch('/测试接口地址', { method: 'POST', body: JSON.stringify({ eventType, details }) }); } 捕获按钮点击事件:获取 id 为 myButton 的按钮,并在其 click 事件上添加监听器。在按钮被点击时调用 trackEvent 函数,记录点击事件的类型(button_click)、按钮 ID 和时间戳。 ...

August 7, 2025

代码分割工程化

什么是 Bundle Splitting? Bundle Splitting(代码分割)是一种将前端资源拆分成更小、独立的模块的技术。传统上,前端资源(如 JavaScript、CSS 和图片等)被打包成单个文件,通常称为“bundle”。这种方式存在一个问题,即无论用户需要哪些功能,都必须下载整个 bundle。而 Bundle Splitting 技术通过将代码拆分为更小的模块,按需加载,可以有效解决这个问题。 Bundle Splitting 的优点 减少初始加载时间 通过将代码拆分为多个小块,可以减少初始加载时间。当用户首次访问网页时,只需下载当前页面所需的资源,而无需等待整个应用程序的加载完成。这可以极大地提高页面的响应速度,并减少用户的等待时间。 提升用户体验 通过将代码分割成模块,可以使应用程序更具响应性。当用户与应用进行交互时,只需加载所需的代码块,而不是整个应用。这将减少不必要的资源消耗,并使用户感觉应用更加流畅和快速。 优化缓存策略 拆分代码还能优化缓存策略。当应用程序发生更改时,只需重新加载发生变化的模块,而不必重新下载整个应用。这减少了不必要的网络请求,提高了应用的更新效率,并减轻了服务器的负载。 并行加载资源 通过将代码拆分为多个模块,可以实现并行加载资源。浏览器能够同时下载多个文件,从而减少整体加载时间。这对于大型应用程序和复杂的前端框架特别有益,能够更好地利用浏览器的并行下载能力,提高资源的加载效率。 代码复用和维护 通过将代码分割成模块,可以更好地实现代码的复用和维护。不同的模块可以根据需求进行加载和升级,使得代码结构更加清晰、模块化。这也有助于团队合作,不同开发者可以并行工作在不同的模块上,提高开发效率和代码质量。 Bundle Splitting 的缺点 增加了网络请求 拆分代码会增加应用程序的网络请求次数。每个模块都需要进行一次独立的网络请求,这可能会导致一些额外的延迟和性能损失。在网络条件较差的情况下,这可能会对用户体验产生一定影响。 增加了开发复杂性 使用 Bundle Splitting 技术需要对应用程序的依赖关系进行深入分析和管理。开发人员需要仔细考虑代码的拆分点,以及如何在运行时动态加载模块。这增加了开发复杂性,并要求开发人员具备较高的技术水平和经验。 潜在的代码冗余 当模块之间存在共享的代码片段时,可能会出现潜在的代码冗余问题。如果不合理地进行代码拆分,可能会导致多个模块中存在相同的代码,增加了资源的下载和维护成本。因此,在进行代码拆分时,需要仔细考虑代码复用和代码冗余的问题。 需要额外的工具和配置 Bundle Splitting 需要使用额外的工具和配置来实现代码的拆分和动态加载。这可能需要对构建工具进行配置,如 Webpack、Rollup 等,以及对模块加载器进行调整。这增加了一些学习成本和开发成本,尤其是对于新手来说。 Bundle Splitting 的适用场景 Bundle Splitting 技术适用于大型的 Web 应用程序,特别是那些具有复杂功能和大量依赖的应用。以下是一些适合使用 Bundle Splitting 的场景: 大型单页应用:对于由多个模块组成的单页应用,使用 Bundle Splitting 可以提高初始加载速度,提升用户体验。 按需加载:对于需要动态加载不同功能模块的应用,Bundle Splitting 可以根据用户的需求按需加载模块,减少不必要的资源消耗。 公共库和框架:对于使用公共库或框架的应用,可以将这些库和框架拆分成单独的模块,以便在多个页面中共享和复用。 国际化支持:对于需要支持多种语言的应用,可以将不同语言的资源文件拆分成独立的模块,根据用户的语言偏好进行加载。 代码分支管理:对于大型团队开发的项目,使用 Bundle Splitting 可以更好地实现代码的分支管理和并行开发,提高开发效率。 Bundle Splitting 在知名项目中的应用 示例 1:React.lazy 和 Suspense React.js 是一个广泛使用的 JavaScript 库,用于构建用户界面。React 提供了 React.lazy 和 Suspense API 来实现 Bundle Splitting。 ...

August 7, 2025

持续集成/持续部署(CI/CD)

传统应用发布模式 开发人员:在开发环境完成代码编写,单元测试,测试通过后提交到代码仓库 运维人员:把项目部署到测试环境,供QA团队测试,测试通过后,部署生成环境 测试人员:进行测试,测试完成后通知运维部署生产环境 缺点 项目在早期就存在错误,但到最后集成的时候才发现 需要手动操作,易错率高 开发与运维需要及时沟通 有了以上缺点,那么就有了CI/CD CI/CD 持续集成(CI): 合并开发人员正在编写的所有代码 一天内进行多次合并和提交代码 从存储库或生产环境中进行构建和自动化测试,确保没有集成问题并及早发现任何问题 持续交付(CD): 可以通过将更改自动推送到发布系统来随时将软件发布到生产环境中 持续部署,并自动将更改推送到生产中 GitLab内置CI/CD 运行流水线任务 Job 在文件中可以定义一个或多个作业,每个作业具有唯一的名称,每个作业是独立执行的,每个作业至少包含一个script stages: 用于定义作业可以使用的阶段,并且是全局定义,同一个阶段的作业并行运行,不同阶段按顺序运行 only: 用分支策略来限制jobs构建 script: 项目中package中的脚本 environment: 定义此作业完成部署的环境名称 下面是每个jobs的详细变量名 Keyword Required Description script yes Runner执行的命令或脚本 image no 所使用的docker镜像,查阅使用docker镜像 services no 所使用的docker服务,查阅使用docker镜像 stage no 定义job stage(默认:test) type no stage的别名(已弃用) variables no 定义job级别的变量 only no 定义一列git分支,并为其创建job except no 定义一列git分支,不创建job tags no 定义一列tags,用来指定选择哪个Runner(同时Runner也要设置tags) allow_failure no 允许job失败。失败的job不影响commit状态 when no 定义何时开始job。可以是on_success,on_failure,always或者manual dependencies no 定义job依赖关系,这样他们就可以互相传递artifacts cache no 定义应在后续运行之间缓存的文件列表 before_script no 重写一组在作业前执行的命令 after_script no 重写一组在作业后执行的命令 environment no 定义此作业完成部署的环境名称 coverage no 定义给定作业的代码覆盖率设置 配置.gitlab-ci.yml stages: - deploy_dev - deploy_test - deploy_production deploy_dev: stage: deploy_dev environment: name: dev only: - dev script: - rsync -av . ${WORKSPACE_PATH} && cd ${WORKSPACE_PATH} - npm run build:dev - ansible-playbook ansible-deploy.yml --extra-vars "hosts=cloud_ui_test projectDir=${WORKSPACE_DIST_PATH} projectName=${PROJECT_NAME} webRootPath=/opt/devroot/" deploy_test: stage: deploy_test environment: name: test only: - master script: - rsync -av . ${WORKSPACE_PATH} && cd ${WORKSPACE_PATH} - npm run build:stage - ansible-playbook ansible-deploy.yml --extra-vars "hosts=cloud_ui_test projectDir=${WORKSPACE_DIST_PATH} projectName=${PROJECT_NAME} webRootPath=${WEB_ROOT_PATH}" deploy_production: stage: deploy_production only: - production when: manual script: - npm install - npm run build:prod - ansible-playbook ansible-deploy.yml --extra-vars "hosts=dvs-front-prod projectDir=${PROJECT_PATH} projectName=xianglin-cloud-ui/${PROJECT_NAME} webRootPath=/opt/" 上面这个.yml文件,我们首先定义了三个阶段,deploy_dev部署到dev环境,并且拉去的是dev分支代码; deploy_test部署到test环境,拉去的是master分支代码,deploy_production拉取production分支代码,执行完后需要手动操作 ...

August 7, 2025

包管理

现如今,前端开发的同学已经离不开 npm 这个包管理工具,其优秀的包版本管理机制承载了整个繁荣发展的NodeJS社区,理解其内部机制非常有利于加深我们对模块开发的理解、各项前端工程化的配置以加快我们排查问题(相信不少同学收到过各种依赖问题的困扰)的速度。 本文从三个角度:package.json、版本管理、依赖安装结合具体实例对 npm 的包管理机制进行了详细分析。 一、剖析 package.json 在 Node.js 中,模块是一个库或框架,也是一个 Node.js 项目。Node.js 项目遵循模块化的架构,当我们创建了一个 Node.js 项目,意味着创建了一个模块,这个模块必须有一个描述文件,即 package.json。它是我们最常见的配置文件,但是它里面的配置你真的有详细了解过吗?配置一个合理的 package.json 文件直接决定着我们项目的质量,所以首先带大家分析下 package.json 的各项详细配置。 1.1 必备属性 package.json 中有非常多的属性,其中必须填写的只有两个:name 和 version ,这两个属性组成一个 npm 模块的唯一标识。 npm包命名规则 name 即模块名称,其命名时需要遵循官方的一些规范和建议: 包名会成为模块url、命令行中的一个参数或者一个文件夹名称,任何非url安全的字符在包名中都不能使用,可以使用 validate-npm-package-name 包来检测包名是否合法。 语义化包名,可以帮助开发者更快的找到需要的包,并且避免意外获取错误的包。 若包名称中存在一些符号,将符号去除后不得与现有包名重复 例如:由于react-native已经存在,react.native、reactnative都不可以再创建。 如果你的包名与现有的包名太相近导致你不能发布这个包,那么推荐将这个包发布到你的作用域下。 例如:用户名 conard,那么作用域为 @conard,发布的包可以是@conard/react。 查看包是否被占用 name 是一个包的唯一标识,不得和其他包名重复,我们可以执行 npm view packageName 查看包是否被占用,并可以查看它的一些基本信息: 若包名称从未被使用过,则会抛出 404 错误: 另外,你还可以去 https://www.npmjs.com/ 查询更多更详细的包信息。 1.2描述信息 基本描述 { "description": "An enterprise-class UI design language and React components implementation", "keywords": [ "ant", "component", "components", "design", "framework", "frontend", "react", "react-component", "ui" ] } description用于添加模块的的描述信息,方便别人了解你的模块。 ...

August 7, 2025

版本控制

什么是版本控制 版本控制是一种系统性的方法,用于管理和跟踪软件开发项目中的代码、文件和资源。它的核心目标是在不同时间点的开发中保持代码的一致性、可追溯性和可维护性。 为什么要做版本控制 这个问题可以从定义中的关键词可以看出端倪:不同时间点下的代码一致性、可追溯性、可维护性。这里额外补充一点:当今的互联网开发早已步入敏捷迭代,各种动态化方案层出不穷都有着顺应时代潮流的意思,因此软件开发一定会越来越多地涉及到团队开发,团队之间的协作也一定需要这样一个机制去保障稳定性。 代码一致性 版本控制系统允许开发人员有效地管理和组织项目中的代码。它跟踪每个文件的历史记录,记录了每个版本的变更,包括谁做了什么修改、何时以及为什么。 可追溯性 版本控制系统允许为重要的里程碑或发布创建标签(tag),以便轻松识别和回滚到特定版本。 并且当某个版本的代码出现问题,版本控制系统允许开发人员轻松地回滚到之前的稳定版本,并在不破坏其余代码的情况下进行修复。 可维护性 开发人员可以创建分支(branch),这是一个独立的代码副本,用于开发新功能、修复错误或进行实验性工作。然后,这些分支可以与主代码库合并,以实现功能集成。 团队协作 在多人协作的环境中,不同开发者可能同时修改代码。版本控制系统确保不同的修改不会互相冲突,以及如何解决冲突。 版本控制系统促进了团队之间的协作,可以通过代码审查工具进行代码审查,以确保代码质量和一致性。 版本控制工具Git Git的安装 WIndows 访问 Git官网,选择对应的操作系统下载即可。 这里下载独立安装包即可 点install就行,会自动安装一个git GUI工具,但通常不会直接用它 下载完成安装即可,输入以下命令验证安装是否成功 git version 图形化工具 安装 这里推荐TortoiseGit这个工具,非常方便。但我觉得Git本身学习成本并不高,GUI工具更多是为了提升效率,基本的Git知识点还是需要掌握的。 下载本体 然后是语言包 安装时一路next即可,安装完本体后再安装语言包。 配置好Github的账户、邮箱、秘钥等,注意配置好了密钥也不会在下述部分显示,可以打开编辑全局进行查看 使用 在使用之前先提前补充一个点(后续会详细介绍),Git有本地仓库和远端仓库的概念,通常支持HTTPS和SSH两种协议进行关联,两种方式优缺点也十分明显: HTTPS:无需额外配置,但是在每次连接远端仓库时需要输入账号密码进行校验。 SSH:生成一组密钥对,需要本地进行配置,好处是配置好后每次连接远端仓库时会自动比较密钥对,无需额外校验。关于SSH详细可以参考这篇文章ssh-远程登录协议 为了一劳永逸,我们这里配置下SSH,首先打开Git bash # 输入下列命令,最后一个参数是您的邮箱 $ ssh-keygen -t rsa -C yourEmail.com 可以看到密钥对已经生成了 进入上述目录,注意.ssh文件夹默认是隐藏的,直接访问路径就行 以Github为例,配置公钥 创建一个Demo项目,平时学习的话就创建公有项目就行 复制一下我们的项目链接 选取一个你喜欢的目录作为本地工作区,然后按鼠标右键 ...

August 7, 2025