All Posts

出去就餐并且理解Express.js的基本知识

Going out to eat and understanding the basics of Express.js出去就餐并且理解Express.js的基本知识 原文:Going out to eat and understanding the basics of Express.js 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 如果你曾经去过一个坐下来就餐的餐厅,那么你可以了解 Express 的基础知识。 但是,如果你刚刚开始构建你的第一个 Node.js 后端……你可能并不会很顺利。 是的 - 如果你曾经有过 JavaScript 经验,学习 Node 肯定更容易。 但是,在构建后端时面临的挑战与在前端使用JavaScript 时所面临的挑战完全不同。 当我学习Node时,我选择了困难的方式。 我一遍又一遍地学习电子书,写作教程和视频,直到我终于明白我为什么要做我正在做的事情。 有一个更简单的方法。 我打算用一个餐馆的比喻来解释你的第一个应用程序的四个关键部分。 Express.js 是一个组织你的代码的流行框架,我会为任何初学者推荐它。 稍后我会进一步解释。 下面是我们将会涉及到的四个关键部分: The require statements Middleware Routing App.

将Medium中的博客导出成markdown

Medium(需要翻墙访问)是国外非常知名的一个博客平台。上面经常有很多知名的技术大牛在上面发布博客,现在一般国内的搬运的技术文章大多数都是来自于这个平台。 Medium 文章格式显示地非常优雅,但是存在一个问题。众所周知,markdown已经是最受程序猿欢迎的文本编辑格式之一。但是Medium仅仅支持markdown格式导入,不支持markdown格式的导出。这也正是我当初开发这个插件export-medium的原因,现在这个项目是放在github上面的,欢迎大家多多star,或者pr。自己也花了5美金,注册了开发者账号,因为现在chrome对于不是商店的插件限制很严格,如果没上商店,一直有提醒,很麻烦。商店访问地址在这,需要翻墙访问。不过你可以手动安装: * 将 export-medium clone 或者下载到本地。 * 在 Chrome 浏览中打开chrome://extensions,加载已解压的拓展程序,选择项目文件夹 这两种方法都是可以支持安装的。目前这个插件的功能主要是把Medium上面的文章解析成 markdown 格式的文本,用了一个简单的库去渲染(事实上我觉得挺鸡肋的),然后你只要点击一个按钮就可以把文本复制到剪切板,就可以复制到编辑器了,是不是很方便。 目前可能很多页面做的不是特别好看,欢迎大家感兴趣的可以试用或者向我提建议。 仓库地址: https://github.com/neal1991/export-medium (喜欢的还请多多star!!!)

Mongoose中document和object的区别

这个问题其实是mongoose非常常见的问题,经常有很多以前没遇到这个问题的人都会被这个问题弄得怀疑人生。我们先介绍一些问题的背景。先看下面一段代码: router.get('/', function(req, res, next) { // res.render('index', { title: 'Express' }); const model = mongoose.model('realestate'); const queryCretia = {}; model.find(queryCretia, (err, docs) => { res.render('index', { title: 'express', docs: docs }) }) }); <!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %></p> <!-- <%= docs %> --> <ul> <% docs.forEach(function(doc){ %> <li><%= doc.type %></li> <% }) %> </ul> </body> </html> 在第一段代码中,通过model.

JavaScript是如何工作的:引擎,运行时间以及调用栈的概述

JavaScript是如何工作的:引擎,运行时以及调用栈的概述 原文:How JavaScript works: an overview of the engine, the runtime, and the call stack 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 随着JavaScript变得越来越流行,团队在多个层级都对它进行利用-前端,后端,混合应用,嵌入式设备以及更多。 正如GitHut stats所展示的那样,JavaScript是Github上面最活跃以及总Push次数最多的语言。在其它类别中也不会落后太多。 (获取最新的 GitHub language stats). 如果项目对于JavaScript越来越依赖,这意味着为了构建好的软件开发者必须利用这个JS提供的一切并且对于生态系统的内部有着更深的理解。 因此,尽管每天有很多开发者在使用JavaScript,但并不知道内部到底发生了什么。 概览 几乎每个人都已经听说过V8引擎的概念,并且很多知道JavaScript是单线程的或者它是使用一个回调队列的。 在这篇博文中,我们将会详细讲述所有概念并且解释JavaScript是如何真正运行的。在了解这些细节之后,你将能够写出能够适宜地利用提供的API的更好的,非阻塞的app。 如果对于JvaScript来说还不是很了解,这篇博文将会帮助你理解为什么JavaScript和别的语言相比如此“奇怪”。 如果你是一个有经验的JavaScript开发者,希望这篇文章能够让你对你每天使用的JavaScript Runtime是如何真正工作的。 JavaScript 引擎 最流行的JavaScript引擎的例子之一就是谷歌的V8引擎。比如Chrome以及Node.js内部就是使用V8引擎。下面是一个简单的视图示例: 引擎主要由两个部分组成: 内存堆——这是内存分配发生的地方 回调——这是你代码执行时的栈帧。 Runtime 有很多浏览器中的API几乎都被JavaScript开发者使用过(比如:’setTimeout’)。然而这些API并不是由引擎提供的。 那么,它们是从哪来的呢? 事实证明这有一点复杂。 因此,虽然我们有引擎但实际上是有更多。我们有那些由浏览器提供的Web API,像DOM, AJAX, setTimeout以及更多。

什么是服务端伪造(SSRF)

什么是服务端伪造(SSRF) 原文:GitHub Pages and Single-Page Apps 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 服务端伪造(SSRF)指的是攻击者从一个具有漏洞的web应用中发送的一个伪造的请求的攻击。SSRF通常适用于针对在防火墙后一般对于外部网络的攻击者是无法访问的内部系统。另外,攻击者也可能利用SSRF来访问监听回送地址接口(127.0.0.1)的服务。 典型的SSRF发生在web应用发送请求的时候,攻击者对这个发送的请求具有全部或者部分的控制。一个通用的例子就是攻击者能够控制全部或者部分web应用向第三方服务发送请求的URL。 下面的是PHP中容易收到SSRF的一个例子。 <?php /** * Check if the 'url' GET variable is set * Example - http://localhost/?url=http://testphp.vulnweb.com/images/logo.gif */ if (isset($_GET['url'])){ $url = $_GET['url']; /** * Send a request vulnerable to SSRF since * no validation is being done on $url * before sending the request */ $image = fopen($url, 'rb'); /** * Send the correct response headers */ header("Content-Type: image/png"); /** * Dump the contents of the image */ fpassthru($image); } 在上面的例子中,因为攻击者对于url参数具有完整的控制,因此能够对于网上的任何网站都能够发送任意的GET请求。攻击者也能够向服务器中的资源发送请求。

通过利用immutability的能力编写更安全和更整洁的代码

通过利用immutability的能力编写更安全和更整洁的代码 原文:Write safer and cleaner code by leveraging the power of “Immutability” 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT Immutability是函数式编程的重要基础之一。它允许你能编写更安全以及更整洁的代码。我将会通过一些JavaScript例子来向你展示如何来达到immutability。 根据维基百科: 不可变对象是一个在创建之后不能修改其状态的对象。这正与可变对象相反,它能够在创建之后被修改。在某些情况下,对象被认为是不可变的,即使其内部的某些属性发生改变,但是从外部的角度来看这个对象的状态看起来还是没有发生变化的。 Immutable数组 数组是理解immutability如何工作的很好的起点。让我们一起来看一看。 const arrayA = [1, 2, 3]; arrayA.push(4); const arrayB = arrayA; arrayB.push(5); console.log(arrayA); // [1, 2, 3, 4, 5] console.log(arrayB); // [1, 2, 3, 4, 5] 这个例子将arrayA的引用分配给arrayB,因此这个push方法在这两个变量中都会添加5这个值。我们的代码间接地修改其它的值,这并不是我们想要的。这也违反了immutability的原则。

菜鸟程序员成长史 --记 Github 1000+ contributions

其实一直以来想写一篇文章总结这几年的技术学习,刚好趁着自己的第一次github contribution 达到1000+,写篇文章总结以下。本文篇幅较长,我会分为几个章节来分别阐述。 博客篇 为什么我要把博客放在第一位呢?因为我认为博客是developer学习技术的平台,也是developer分享知识的平台,博客差不多也就相当于是developer的名片。现如今,博客平台形形色色,有老牌的博客园,CSDN,也有现在比较新潮的SegmentFault,掘金,开发者头条,知乎等等。现在博客的形式已经发展得多种多样,现如今新潮的犹如各种各样的专栏等等。当然,在这么多博文中,有很多质量很高的文章,也有很多滥竽充数的垃圾文章。下面,我就就我个人的了解探探我接触的这些博客平台,仅是个人观点。 Github 哈哈。我为什么把Github列到博客篇呢?其实现在Github几乎已经成为了我生命中不可或缺的一部分,每天打开电脑的一件事,基本就是打开Github看看。作为世界上最大的同性交友网站,Github对于程序猿来说绝对是生命中不可或缺的部分。在此,我主要说说Github作为博客方面的内容。 很多人认为Github只不过是一个代码托管的地方,为什么会和博客有关系呢?其实,现在很多人都是在Github的issue里面开博客,因为issue里面方便作者和读者的沟通,而且支持markdown格式,各种功能也是很丰富。对于比较关注的博客,你可以设置watch,这样你就可以了解issue里面的每一次变化,并且还会有相应的邮件通知。在此,给出几个我关注的几个人的Github博客: iCSS:讲解CSS的,有的还是蛮有趣的。 梁少峰的个人博客:讲解vue讲解的很透彻,百度大牛,我觉得有些博文挺值得看,而且值得多看几遍,不过我好像都没看完。他的博文还是需要深度挖掘的。 ccforward/cc:应该是当初关注他的一个知乎爬虫,他的博客内容我没有看太多,但是内容貌似还不错。 underscore-analysis:解析underscroe源代码的,挺不错的,我看过一两篇,值得多读几篇,我自己也该去读了。 Front-end-tutorial:内容很多,我没有过多了解,可以了解一下。 以上就是我了解的一些在Github上面的博客,因为在Github我没有特别关注这方面,所以还不是特别多,当然Github也不是我主要逛博客的地方。 CSDN CSDN是我开启个人技术博客的地方,感兴趣的地方去我的博客逛逛http://blog.csdn.net/neal1991 。我应该是从2015年4月份开始写博客的,博客的内容主要有我研究生期间一开始做的道路识别的一些研究的论文,虽然这个方向没搞下去,这个方向的确很有前景,只能说老板很有眼光,但我没能力,没能搞下去。其它的也包括一些开发过程遇到的坑之内的,面试经历,技术文章翻译。老实说,CSDN现在的确不是一个很好的平台,因为本身它就偏老,在markdown的显示不是很完美,在移动端显示不是很好,还有一点很重要,广告特别多,还是莫名其妙的,看起来很讨厌。其实我一直都想弃坑,奈何就是github国内访问速度不稳定,还有毕竟在这边维护这么久了,所以还是一直维护着。在CSDN上,我基本上都是去写博客,基本不会在它上面浏览技术博客,因为它的浏览界面实在是太杂乱了,没有重点。这可能也是老牌博客的一个缺点,可能一时半会也没办法改过来。下面我主要讲一些我自己的一些比较稍微有用的博客内容: combox系列问题集:当初做winform开发遇到的问题,记得当初最坑爹的是调试combox的时候,visual studio老是崩溃,后来发觉居然是有道翻译的锅,也是醉了。。。 独立成分分析:这个应该是当初一个讨论班里面要做的一个presentation,我把内容整理出来写了这篇博文,阅读量快2000了,好像是我博客里面阅读次数最多的了。 如何查找django安装路径:非常简单的一个问题,但是当初搜遍了,没找到解决方法。 mongoose对象无法新增删除属性:当初在处理mongo遇到的一个问题,是个坑。 第一个chrome extension:第一次写chrome extension,没有想象中的那么复杂,不过还是有一些方法的,貌似360有翻译过谷歌相关的文档。老实说,谷歌真的很良心,现在很多开发者文档都已经是中文的了。 第一个pwa:第一次写progressive web application,其实写pwa和写其它单页面应用没有特别大的区别。pwa也是我非常看到的技术栈,我觉得这个比小程序好上一百倍,只不过现在在国内还是不温不火,但是我觉得很肯能哪一天就星星之火,可以燎原了。 鉴于CSDN平台的种种,我的确越来越不太愿意在这上面写文章。而且我最近的文章一向是以翻译国外技术文章为主,毕竟还是菜,所以只能靠英语吃饭啦。 掘金 老实说,掘金应该是同类这种网站访问量比较大的。的确,里面有不少的精品内容,当然也会参杂很多乱七八糟的东西。其实,现在一般的原创博主都不会只在一个平台发文章,所以基本上你这个平台看得到的,在其它平台也差不多都能看到。只不过我现在基本不看掘金了,因为他们的编辑对新人极度不友善,极度不友好。 众成翻译 360的一个专门翻译技术博客为主的平台,目前应该还是比较小众。360的前端其实还是蛮不错的,尤其是他们的齐舞团队,里面也有很多大牛。这个平台里面的文章一半质量还是比较高的,而且这个平台翻译操作也是蛮舒适的,感兴趣的非常值得试一试。而且他们的群沟通都很流畅,不像掘金那帮人。。。无力吐槽。 知乎 我本身一向是很排斥知乎的。讲心里话,知乎里面百分之八十的人都是在写故事,骗关注的,我也不明白知乎为什么充斥了这么多天天无事可做的人。当然,不可否认的是,知乎里面还是存在百分之二十的精品内容的,这也是让我能够忍受那剩余的百分之八十垃圾的原因。知乎里面那些回答我觉得没有太大的意义,看了也就是笑一笑,一般都是用来刷新三观用的,在此,我仅说一些技术专栏: 饿了么前端:饿了么现在前端的确搞得风生水起,尤其是pwa,感觉他们是这方面搞得国内最为成熟的一家。可能并不是,但他们肯定是分享这方面内容最多的公司。感觉饿了么前端蛮多大牛,不过感觉他们都喜欢混国外圈,黄玄基本都是在medium发文章的。。。 某熊的全栈之路:这个应该是infoq的专栏,这个编辑每个礼拜会发一个国内外最新技术的文章集合,基本是前端为主。内容比较新颖,基本上最时髦的都在这里面。 Think In Vue:意如其名,现在vue在国内真的很火。火到我觉得用react的撕逼应该撕不过vue,vue的作者尤雨溪在知乎也是很活跃的,经常手撕任何喷vue的人,还有看他阮一峰每日一喷很有意思。阮老师也是个很有意思的人,感觉天天都有人喷他,但是阮老师的心态丝毫不受影响,剖有大师风范。不过值得一提的是,阮老师博客的广告位可价值不菲哦~~ 美团点评技术博客:算得上是大厂,值得一看。 知乎乱,前端乱,如何乱中取胜,就是要保持一颗平常心。 开发者头条 不温不火的平台,文章质量还行。我一般发文章这个里面也会发一份。感觉里面的内容偏机器学习以及架构方面,而且这发文章可以攒IO币,可以换书哟。 Medium 国外的一个博客平台,访问需要翻墙。这是国外一个专门写story的地方,样式很好看,应该算得上是国外非常知名的一个博客平台了。当然了,里面的内容也是多姿多彩的,同时里面的技术文章质量也有很多很高的文章。现在国内技术圈翻译的大多数文章基本都是来自于这个平台。 Quora 国外一个和知乎一样的网站。不过知乎由于国内人数优势,火爆异常。Quora则是不温不火,而且上面还有不少华人。我关注过一段时间,但貌似都没什么特别的内容。 以上基本就是我所有的对于一些博客平台的了解,可能不包含所有,但基本都是我自己的个人的亲身经历。可能部分言辞颇为激烈,但也都是我的肺腑之言。 微信公众号 微信公众号作为一种特殊的平台,现在也成为一种传播渠道,有点类似于报看订阅的形式。但这不一定是一种非常有效的传播方式,感觉深度还是不够的,我比较喜欢在电脑上看文章,因为在手机上看文章难以持续地专注于一篇有内容的文章,一般就只能浅尝则止。所以我一般都是把链接转到我的微信PC版,然后再用浏览器打开,下面介绍一些我关注的一些技术类公众号: 前端之巅:我之前提过的,应该是infoQ的平台,其实和之前的知乎专栏应该是重叠的。 奇舞周刊:360奇舞团队,前面也介绍过了,国内的知名的前端团队,会有一些比较有价值的文章。 前端早读课:每天早上都会发送推文,但是文章质量嘛,参差不齐,基本上都是别人的文章。 FEX:百度FEX团队,收集最新技术文章,但是排版比较差,比较原始。 神秘的程序员们:里面会有一些脑洞大开的漫画,而且会有程序猿和产品经理以及架构师撕逼的故事,很有趣。 Github 为什么我要把Github单独作为一章节来讲呢?因为它实在太重要了!!!以至于我除了它,根本不想去尝试其它类似的平台。关于Github可以讲的东西太多太多,它带给程序员的则是无穷的魅力。在此,我也仅就几个方面谈谈我的个人理解: star篇 Star是衡量一个开源项目是否受欢迎的重要标准之一(当然也有很多是骗star的)。其实,现在很多人看到一个项目都会去star,但是后续是否会关注,当然也就不一定了。曾经有一段时间,我对star深深着迷(其实现在还是很着迷),我每天都希望有人能给我的项目star,看着别人上千的star我都会超级羡慕。但我其实也能够深深体会到做一个开源项目的不容易,开发者有一个idea往往很简单,但是要去实现它,推广它,完善它。这真的很难很难,而且还会有各种各样形形色色的人问你各种问题,给你提出各种要求,这些都是很痛苦的。但是我依然希望自己有一天还是能够成为一名出色的开源项目的开发者。下面我就挑一些我star的项目来讲一讲: prepack:前几天,前端圈最火的技术,编译优化,facebook总是走在潮流之端。

基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]

基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1] 原文:基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1] 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 渐进式web应用是大势所趋。越来越多的大公司开始使用这些技术(比如推特:https://mobile.twitter.com/)。 想象你可以在地铁中浏览一个web应用,这个应用能够向用户推送通知并且提供实时的数据,以及提供类似于app的浏览,这些就是PWA的大致的能力。 渐进式web应用(PWA)是一个web应用能够提供给用户一种类似于app的体验。PWA得益于现代web科技创新(Service Workers, Native APIS, JS famework)以及提升的web应用质量标准。 如果你想了解更多关于PWA,请访问这个很棒的Google developer page。 看一下下面的PWA!看起来很像原生的app,是不是? 推特渐进式web应用 从开发者的角度来看,PWA相对于原生应用具有巨大的优点。它基本上就是一个网站,因此: 你可以选择任何你喜欢的框架来进行开发; 一段代码搞定一切:它是跨平台的以及跨设备的(代码是通过用户的浏览器执行的); 很容易获得:不需要通过应用商店来下载。 然而,在2017年早期,PWA仍然面临一些限制条件: Safari不支持一些基本的PWA特性,比如 Service workers,但是苹果公司似乎已经准备开始着手了; 一些原生的函数依然没有得到支持:对于更多信息,浏览这个页面What web can do。 教程目标 本教程的目标是利用VueJS以及Webpack从头创建一个基本的但是完整的渐进式web应用。我们的应用将会满足介绍里面的所有需求:渐进式的,响应式的,连接独立的等等。我想给你一个能够在PWA内完成的目标的总览:流畅的原生式的应用,离线行为,原生特性结构,推送通知。

service worker介绍

原文:Service workers explained 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 那么它是什么? Service worker正是被开发用于解决web平台上经常出现的问题和疑虑,包括: 无法解释(Extensible Web Manifesto 中)的HTTP缓存以及高级HTTP交互比如HTML5 AppCache。 难以自然地构建一个离线优先地web应用。 缺乏可以利用很多提出功能的上下文执行。 我们也注意到了声明解决方案(Google Gears, Dojo Offline以及HTML5 AppCache都没能实现他们的承诺。每个连续的仅有声明的方法都以相同的方式失败了,所以service worker采取了一个不同的设计方法:一个可以用开发者牢牢把控的重要系统: Service worker就好像它的内部有一个有一个shared worker : 在它自己的全局脚本上下文中运行(通常是在它自己的线程中) 不会和特定的页面绑定 不能够访问DOM 不像shared worker,它: 即使没有页面也能够运行 如果不使用的话可以终止,还可以再次运行当需要的时候(比如,他不是事件驱动的) 拥有一个定义的升级模式 只允许HTTPS(更多的是在这一点上) 我们可以利用service workers: 利用网络拦截可以让让网站更快以及/或者支持离线使用 作为其它’background’功能的基础比如消息推送以及后台同步 开始 首先你需要注册一个service worker:

service worker之cache实践--sw-precache

Progressive web application是谷歌推出的一种渐进式应用,我觉得其实PWA是一种非常具有发展前景的技术。首先,PWA是由谷歌推出的,而且跨平台,PWA可以给你类似于原生APP的体验,通过service worker,你可以将资源缓存到本地。但是,PWA再国内一直都是不温不火,主要有好几个原因:一是因为国内的浏览器环境比较复杂,而PWA一般只是能够在chrome浏览器得到较好的支持。虽然chrome在桌面端占据了很大比例,但是在移动端还是一般般,普通的用户不一定会去安装Chrome。二是safari浏览器对于PWA的支持不是很完美,service worker目前还是没有得到支持的。 但是我是觉得PWA还是很好的,值得开发者们进一步探索。有一点偏题了,今天要讨论的其实是PWA里面service worker资源的缓存问题。主要问题的背景是这样的,我有一个上海地铁线路图的PWA,可以支持离线使用,有兴趣的同学可以尝试看看。我遇到一个问题,就是每次我更新之后代码之后,加入我的PWA被添加到主屏之后,这个APP的代码就没有更新,必须删除后重新重浏览器中添加到主屏。一开始我以为是PWA的问题,后来竟别人提醒,桌面上的APP其实也就是网站的链接。我这才恍然大悟,问题是因为我的servicer worker里面的缓存策略有问题。因为我的APP通过service worker来缓存资源,包括js,css以及图片文件,所以始终是从缓存中加载资源,所以我远程代码更新后,这个APP的代码却没有得到更新。OK,拿代码说话,我一开始的代码是: var cacheName = 'subway'; var filesToCache = [ '/', 'index.html', 'image/transfer.png', 'dist/alloy_finger.js', 'app.css' ]; self.addEventListener('install', function(e) { console.log('service worker install'); e.waitUntil(caches.open(cacheName).then(function(cache) { console.log('serviceworker caching app shell'); return cache.addAll(filesToCache); })); }); 可以看出我们在 install 事件后通过在 cache 里面加载文件,所以我们必须选择一种合适的策略能够让我们的APP在代码更新之后去请求新的代码呢? Google其实在PWA推出的过程中也给出了很多有用的技术。比如sw-precache以及sw-toolbox,以及最近正在发展过程中的sw-helper。这里,我主要使用的是sw-precache来更新我的service worker策略。 sw-precache也是NODE中的一个模块,可以通过npm install sw-precache来进行安装。sw-precache可以配合多个工具使用,这里我主要介绍一下如何配合gulp来使用。我们通过利用sw-precache来帮助我们生成sw-precache。饿了么的huangxuan在medium写了一篇文章来渗入地介绍sw-precache,这篇文章写的不错,但是却是在墙外,主要是介绍sw-precache的工作方式。我就谈一下我对sw-precache的理解把,以一个gulpfile的一段代码为例: gulp.task('generate-sw', function(callback) { var path = require('path'); var swPrecache = require('sw-precache'); swPrecache.write(path.join('sw.js'), { staticFileGlobs: [ 'app.js', 'dist/alloy_finger.js', 'dist/app.css', 'image/*.{png}', 'index.html', '/' ] }, callback) }) 我们通过利用 sw-precache 来生成 sw.