以下分享资料为 2022 年 3 月 11 日晚我在统信软件分享的内容《开发者关系与企业业务》


以下分享资料为 2022 年 3 月 11 日晚我在统信软件分享的内容《开发者关系与企业业务》

在开发 Gutenberg 插件时,经常会出现下面这样的提示:
Uncaught Error: Minified React error #231; visit https://reactjs.org/docs/error-decoder.html?invariant=231&args[]=onClick&args[]=object for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Code language: PHP (php)上述提示表示当前的编辑器中出现了一个错误,但由于 React 的 Minified 设置,这些错误没有办法被打印出来。
在这种情况下, React 接管了默认的报错,让应用不至于崩溃,但另一方面,也让我们失去了处理这些问题的可能。因此,在本地的开发环境,最好还是将这个功能给关掉。
在 wp-config.php 文件中添加如下代码即可。
define('SCRIPT_DEBUG', true);
Code language: JavaScript (javascript)
我最近开始日更博客,开始逐渐捡起我的写作的习惯,并尝试以此维持生计。
不过,我自己写文章有个坏毛病,比较意识流,这使得我的文章当中会出现很多的错别字。由于心流作用的存在,写作时我自己无法发现这些问题。
所以,我会在写完文章后,将其复制到微信公众号后台,并使用微信公众号后台自带的语法检查工具,来完成中文的基本信息的检查,降低我的错误率。
当然,除了微信公众号,你还可以有很多选择,比如 飞书文档、石墨文档等。
只是我为了让自己能够用的更爽,自己做了个插件 —— https://wordpress.org/plugins/wpstoreapp-spellcheck/

在大型企业当中,往往会有各种各样的 CI & CD 工作流来完成项目的部署,而对于我自己的项目而言,我也希望能够有这样顺畅的交付体验,因此,我也为自己的业务加上了类似的方案,以实现顺滑的开发体验。
不过,我没有做的那么重,没有上 Ansible,也没有封装 Docker,就是标准的 LNMP 环境。只不过,我在标准的环境上加入了 Laravel Envoy — 一个快速部署工具。
Envoy 是 Laravel 团队开发的一个在远程服务器上执行某些命令的工具,因为他同样使用 Blade 语法,因此在 Laravel 项目中接入非常方便。
Envoy 有多种使用方式,一种是跟随项目的使用方式,即使用 composer require laravel/envoy --dev 来安装,并使用 php vendor/bin/envoy 的方式来运作,这样的好处是你无需污染顶级目录,只在项目层面使用 Envoy 来进行部署。
不过我因为有很多项目,所以我会更加倾向于直接在全局安装 envoy,执行 composer global requre laravel/envoy 实现在全局安装 Enovy。全局安装完成后,当你需要执行命令,只需要执行 envoy run deploy,就能执行当前目录下所定义的命令。
除了全局安装,你也可以考虑使用 Bash alias 来实现类似的效果,将
envoyalias 给php vendor/bin/envoy就可以实现即使没有全局安装,也可以实现不需要手动输入前缀的特性。
当你需要配置时,你要做的很简单,只需要执行 envoy init 服务器地址/昵称就可以获得一个 Envoy.blade.php 文件,你可以通过修改这个文件的内容,来实现定义不同的工作。同样的,你可以将这个文件纳入到版本控制系统当中,从而实现部署脚本的跟踪和定义,对于后续的持续维护比较有帮助。
因为 Envoy.blade.php 也是采用了 Blade 的后缀,所以也同样适用了 Blade 引擎,你可以通过一个语意更加友好的方式来定义你的脚本。
@servers(['web' => '127.0.0.1'])
@task('deploy')
cd /path/to/site
git pull origin master
@endtask
Code language: PHP (php)比如,上面的脚本就是一个最基础的脚本,首先定义了这个脚本的命令会在名为 web 的服务器上执行,而这个服务器的地址是 127.0.0.1;并定义了一个任务 deploy。
当你完成代码的编写,并提交了 Git 之后。执行命令 envoy run deploy ,就会自动的在 web 这个服务器上执行在 deploy 当中执行的命令。
deploy 的命令只要是正常的 bash 命令即可。
因为 Envoy 使用 Blade 语法来编写,你也可以使用 Blade 语法中的命令来引入其他文件的中的任务。因此,你可以将自己常用的命令定义出来,并将其通过 Packagist 发布出去,并在实际应用过程中,引入对应的文件来使用。
@import('vendor/package/Envoy.blade.php')
Code language: JavaScript (javascript)Envoy 支持定义多个服务器以及并行执行,对于架构相对复杂的业务,你可以定义不同的 servers ,并在对应的 task 当中来设定需要在哪些 Server 上执行。定义任务时,如果你传入了 parallel 参数,则可以控制命令同时在多个服务器上并行(该属性为 false 时则是串行(
@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
@task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true])
cd /home/user/example.com
git pull origin {{ $branch }}
php artisan migrate --force
@endtask
Code language: PHP (php)你可以在 Envoy.blade.php 中加入 @setup 来完成变量的定义,并在后续的代码中使用。
@setup
$now = new DateTime;
@endsetup
Code language: CSS (css)也可以直接使用 @include 来引入文件
@include('vendor/autoload.php')
@task('restart-queues')
# ...
@endtask
Code language: PHP (php)在启动时,如果你使用诸如 --param=value这样的参数来调用,则可以在你的代码中直接读取对应的变量,从而实现执行时带入不同的参数。
Envoy 当中还有更多的用法,这里不再一一列举,如果你感兴趣,可以直接参考其官方文档,了解如何使用 Envoy 达成你的部署目标。
在你不是很着急使用 Ansible 或 更重的部署工具的时候, Envoy 是一个不错的选择。特别是你使用 Laravel 进行开发时,Envoy 就是一个有效的工具。

多年来,我一直是 PHP 的拥趸,不论中间我写过多少编程语言,但我始终觉得,PHP 能从 2000 年活到现在,是有其意义和价值的。
而到了现在,我终于可以回答这个价值和意义到底是什么 —— 什么样的业务,使用什么样的架构。
作为技术创业者,我们最常遇见的问题,便是过度设计技术方案:我的项目是不是应该做个数据库主从备份?我的项目是不是应该做 Kuberentes 集群来处理弹性?
但实际上,对于绝大多数的业务而言,这些问题都是根本不重要的 —— 如果没有 Kubernetes,我们能否保证我们的业务的稳定性?如果没有主动备份,我们能否保障我们的业务可以平稳运转?
技术在绝大多数的业务中,都是一个成本中心,是一个保障业务正常运转的基石。他应该被重视,但不应该被过度重视。一个创业公司可能会因为业务不够稳定而失去用户,但绝不会因为业务非常稳定而留住用户。用户在乎的是你为用户解决了什么样的问题,而不是用了什么样的架构。
过度(提前)优化是万恶之源。

今天在和 @bobo 聊天的时候,讨论起了摊销这个话题,我觉得很有价值,因此记录下来。
事情的前提是出于控制开支的目的,我在 2022 年为自己定下了 10000 元的数码设备采购预算,这个预算是考虑到我不需要在 2022 年更换手机( 2021 年刚换了 iPhone 13 ,我的预期是用到 2024 年),我不需要在 2022 年购买新的相机(我已经有了 6400、ZV1、G7X3,主要的几个需求都满足了,唯一希望买的是 GR3/GR3X,但不是特别急),唯一想要买的就是 采用了 M2 的 Macbook Air(32G 内存,512 GB ~ 1TB 的 硬盘),但我不确定新的 Macbook Air 能够在我的预算内解决,所以其实一直比较忐忑是否能买。
不过,今晚和bobo聊的时候,他提出了一个方案,或许可以解决我的问题 —— 摊销。
虽然我今年给自己定的数码设备的预算是有可能无法满足我的采购诉求,但我可以借助于信用卡本身的 24 期分期付款的方式,来实现需要单次支出的成本被摊销到接下来的 24 个月里,这样虽然我支付的钱没有变少,但却将整体的记账周期拉长,从而实现了我在今年的预算不会超出预期。
通过摊销,我超期消费了明年的预算,解决了今年的问题,确实是一个很好的解决方案(当然,也是信用卡分期的意义)。不过,这也反过来让我思考企业的预算和摊销体系,可能作为一个员工,我们会认为思考预算是有点奇怪的,业务随时可能增长,预算必然被打破,但换个角度来看,如果我们的预算在可控范围内进行增长,就可以在享受到摊销带来的价值的同时,不至于过度消费未来。
我近几年一直在用 MoneyWiz 在记账,之前也写过一些关于关于 MoneyWiz 的文章
得益于 Moneyiwz 的预定功能,摊销也可以以一个十分轻量的方式来完成,现在,我更期待今年的发布会了!。

对于生活在中国互联网环境中的开发者来说,ICP备案(后称「备案」)是一个很难绕过去的话题,但凡你需要正经的建设一个网站,那么备案就是一个必须要做的事情,不然可能会出现各种奇奇怪怪的问题。但,你是否思考过,为什么我们需要备案?你是否了解过备案二字背后的深层含义?
备案的要求和历史,可以追溯到 2000 年 9 月 20 日国务院第 31 次常务会议通过的一个管理办法 —— 《互联网信息服务管理办法》(后称信息管理办法),由时任总理朱镕基先生签发。后续我们所进行的一切备案工作,其实都是这个信息管理办法的延展。
在《互联网信息服务管理办法》当中,第二条说明了什么样的情况才需要进行备案:在中国境内从事互联网信息服务活动。
第二条 在中华人民共和国境内从事互联网信息服务活动,必须遵守本办法。
互联网信息服务管理办法, 2000 年 9 月 20 日
这一条也解释了,为什么 Facebook、Google这些网站也可以正常运转,因为他们严格意义上来说,并不算在中国境内从事相关的信息服务活动(但也没保证你一定能够访问)。同样的,如果你自己的网站托管在海外的服务器上,一样不需要备案(但同样不保证你一定能访问,毕竟你不在境内提供服务,网络出现波动啥的非常正常)。
圈定了范围之后,第三条规定了不同的互联网信息服务都是什么样的类型,进行了定性操作。
第三条 互联网信息服务分为经营性和非经营性两类。经营性互联网信息服务,是指通过互联网向上网用户有偿提供信息或者网页制作等服务活动。非经营性互联网信息服务,是指通过互联网向上网用户无偿提供具有公开性、共享性信息的服务活动。
互联网信息服务管理办法, 2000 年 9 月 20 日
而在完成了定性操作后,紧接着在第四条声明了不同服务类型应该执行的策略:经营性采取许可制度,非经营性采取备案制度。
第四条 国家对经营性互联网信息服务实行许可制度;对非经营性互联网信息服务实行备案制度。
互联网信息服务管理办法, 2000 年 9 月 20 日
至此,我们熟悉的 ICP 备案走上了台前。而我们现在了解到的各种具体的备案的细节,则是在管理办法内容的延展,如果你对于这些内容感兴趣,可以详细的阅读这个信息管理办法。
在 2005 年 1 月 28 日,在《互联网信息管理办法》之上的细分管理办法《非经营性互联网信息服务备案管理办法》(后称非经营性管理办法)也相应出台,对于非经营性互联网信息服务进行了更加明确的安排和说明。我们所熟悉的备案登记表、省级通管局、网站底部公示备案编号等描述也出现在了非经营性管理办法当中,网站的备案事项,也正式被推行。
备案对于很多人来说,最麻烦的不是搞不清楚怎么备案,而是搞不清楚如何处理域名、网站、 服务器、个人之间的关系。而所有的这些关系,其实可以用一个词来说明 —— 「双绑定制度」。
现行的网站备案制度其实是一种“双绑定制度”,一方面将网站和所有人绑定在一起,另一方面,将网站和它的接入商绑定在一起。一旦某个网站出现了问题,则需要能够在第一时间找到网站的所有人和接入商。
阮一峰,《关于网站备案,》,2009年 9 月 9 日
备案并非一个阻拦性措施,而是一个监管性措施(对比经营性互联网信息服务的许可制),希望大家可以积极踊跃的进行互联网信息服务的同时,避免恶劣影响的网站持续提供服务。找到接入商来第一时间拔网线,缩小影响范围;找到所有人来进行相应的处罚。
当我们搞清楚了备案的核心理念和目的之后,我们重新回过头来看看备案当中的五个关键角色:备案主体、省通管局、接入服务提供商、域名注册商和域名管理机构。

当我们真正开始进行备案时,就会面临三个元素:域名、服务器、所有人。这五个关键角色与三个元素,依次发生关系。
当我们开始思考建设一个网站时,必然会涉及到域名的问题。而实际上自 2017 年 11 月 30 日颁布的《工业和信息化部关于规范互联网信息服务使用域名的通知》正式实行之后, 并不是每一个域名都能够完成备案。在该通知中,要求互联网域名注册服务机构要在我国进行相应的注册和审批,才能够让对应的后缀进入到备案的流程。如果对应的域名注册服务机构没有在我国进行注册,则对应的域名无法在我国进行备案。
从而,也就出现了现在很多时候我们在购买域名时候需要考虑的一些问题 —— 域名能否完成备案?
目前所有完成了相应注册机构的审批都可以在工业和信息化部域名行业管理信息公示网站找到。如果你需要购买域名且有打算在国内进行备案,则一定记得确认你所购买的域名是否可以在国内完成备案的流程。
此外,如果你感兴趣的话,还可以在这里找到一些你可能从来都没听说过、没见过的后缀,比如.baidu。
对于已经进行的域名注册服务机构,因为工信部有了相应的沟通方式,则可以在出现问题后,下发公函,要求对应的服务机构协助调查和配合。而对于没有注册的管理机构,无法完成相应的配合,干脆不予后缀备案。
这也解释了为什么现在你购买的 .io 域名不能备案,因为对应的注册管理机构没有在我国注册,不符合备案的要求。至于你看到的那些有备案号的 .io 域名,则是在相应的通知发布之前完成的备案,故而可以正常使用。
当你选择了一个可以进行备案的域名后缀(比如 .com)之后,就可以进行域名的注册了。域名的注册需要到对应的域名注册商来完成。这个时候,也会涉及到不同的域名注册商可能会影响你的备案流程。
按照新的管理办法,你的域名需要在购买的时候完成实名认证。因此,你如果域名想要备案,则要求你的域名注册商支持进行实名认证。
比如,目前你可以在阿里云(万网)、腾讯云(新网)、西部数据等域名注册服务提供商这里购买域名并进行实名认证,在实名认证完成后,再进行后续的域名备案操作。
相应的,对于域名注册服务机构,也采用了审批和注册的限制,不同的服务商能够支持的域名实名认证也是不同的,企业需要根据「互联网域名注册服务机构审批」来进行提交,等待审批通过后,才能提供相应的域名注册和实名认证服务。
目前通过审批的域名注册服务机构也可以在工业和信息化部域名行业管理信息公示网站找到。
这也解释了为什么你在 Godaddy 、Namesilo、Namecheap 之类的域名注册机构注册的域名无法在国内进行备案,因为他们并没有在国内注册,接入相应的实名认证流程,自然无法为你提供后续的备案服务。
当你选择好了域名后缀和域名注册服务商,进入了详细的域名注册流程当中时,会涉及到域名的实名认证的环节。
在这个时候你需要注意,备案要求域名实名认证和备案的主体是保持一致的,因此,如果你后续打算以哪个主体(个人或者企业)进行备案,在这里进行实名认证时,就要选择对应的信息来进行实名认证。
你提交信息后,域名注册服务机构(域名注册服务商)就会将你的域名和对应的实名信息提交到工信部。一般 1 ~ 2 个工作日后,你的信息就可以在工信部的内部系统可查,这个时候才能进行下一步的备案。
域名购买好了,接下来就是选择接入服务提供商。由于备案实际上是个人与网站、网站与接入服务商进行的「双向绑定」,因此,能够提供备案服务的服务商都是在工信部进行了相应的注册的服务商(需要持有互联网数据中心业务经营许可证)。
在进行备案时,会要求你的域名已经完成了实名认证,然后再提交信息进行相应的备案,这里会要求域名的实名认证和接入服务提供商的实名认证信息保持一致,进行审核。
这也解释了为什么你购买的 DigitalOcean 的服务器无法进行备案,因为 DigitalOcean 并不持有互联网数据中心业务经营许可证。当然, DigitalOcean 的服务器也不需要进行备案。
当你进行备案时,会让你选择一个备案的所在地,备案的所在地决定了你的网站归属于哪个省份的通信管理局来进行管理。
一般来说,大家会选择身份证所在地。当然,如果按照惯例办法中的说明了,其实你还可以选择你的当前所在地(因为管局在乎的是能否联系到你)。选择了对应的省份,需要你提交相应的信息(需要能够精确到门牌号),基于对应的信息来进行备案。不过需要注意的是,不同的地区可能有所不同,比如基于当前所在地的备案可能会要求你提供居住证来进行备案。
理论上,你可以拥有多个不同的备案号,一个身份证所在地的备案号,和多个居住地所在的备案号。
当你准备好所有信息,接入服务商帮你进行了基本的审核后,就会将你的信息提交至你备案的对应的通管局。而 ICP 备案本身是备案制度,因此,审批其实大部分情况下都是能够通过的,只是说需要一点时间,不同的省份在备案的审批上所需的时间也不同,根据《非经营性互联网信息服务备案管理办法》的要求,会在 20 个工作日内完成审核。不过某些特定的省份是比较快的(比如上海、浙江,据说是可以 1个工作日完成审批)。
当你完成审批后,就会获得一个备案号,将对应的备案号放置在你的网站底部,并加上前往通管局的链接即可。
当你完成了第一个网站备案和建设后,你可能会需要进行第二个网站的备案和建设,这个时候,你需要注意:
这就要求你如果某个域名不再使用,尽快将其关闭,并注销域名和相应的备案。
当你拿到域名备案号之后,你就可以在你办理备案的接入服务商进行网站的建设和开发工作了。但需要注意的是,你仅能使用当前办理了接入服务商的服务,如果想要使用其他家的服务,则需要再次办理接入,新增一个接入,以使用对应服务商的产品。毕竟,备案的核心诉求是「双向绑定」,绑定用户和网站、网站和接入商。你虽然完成了备案,解决了用户和网站的绑定,但如果你没有完成网站和接入商的绑定(做接入备案),接入商同样会拒绝为你提供服务。
此外,需要注意的是,你的名下应当始终至少有一个网站,对于一个网站都没有的(比如你注销掉了所有的网站)人,在备案系统中被称为「空壳主体」,通管局会定期清理空壳主体,所以为了保住你的主体和备案号,尽量保证你的名下有网站。如果需要迁移服务商,也在完成了新的服务商接入之后,再注销之前服务商的接入。
在备案体系中,有一个很独特的产品 —— CDN 。和云主机不同,云主机会要求进行接入后才能使用,而 CDN 则没有相应的要求,你只要完成了备案,无需再进行接入即可使用 CDN 。
CDN 作为一个分布式的产品,因为没办法统一进行接入,故而只做了备案的限制,而不再要求你的域名必须在对应的服务商进行接入。
其实前面说了那么多,都是一些知识性的内容,接下来,我们来面对一个真实世界的问题 —— 如果某个网站出现了问题。可能会怎么处理?
前面说过,备案本质上是为了能够在出现问题后快速找到你,解决网站中的问题。但真正在执行时,可能会有哪些操作?
这篇文章写完了,让我心头一松。我从 2012 年开始建立个人网站,2013 年、2014 年开始备案第一个域名,后续在 2016 年,在网易实习时以接入服务商视角看待了备案,再到在线,备案的政策不断的变化,我自己从某种意义上也经历了备案从松到严的一段历程(虽然没有经过最松的那段时间)。
备案机制从很多从业者的角度来看,觉得是繁文缛节,但换个角度来看,也是为我们的互联网提供了一定的基本保障制度。互联网上的信息良莠不齐,备案虽不能以黑名单的机制保证我们所看的信息“绝对干净“,但却也以白名单的方式给了一些建议。
不过,这篇文章也有遗憾,因为篇幅限制,我未能介绍关于公安备案相关的信息,这部分就留作后续再独立成文来介绍吧。

在进行网站建设的时候, SSL 证书是一个可以有效的提升网络数据传输过程安全性的手段。而一般来说,大家可以选择直接购买 SSL 证书或使用 Let's Encrypt 提供的免费证书。但 Let's Encrypt 的证书问题在于往往是短期证书(比如三个月),如果要使用在 CDN 上,就会需要经常替换,非常的麻烦。
目前各家云厂商大多都提供了免费的 SSL 证书,方便大家使用,不过有些时候入口比较深,所以大部分人找不到,只能购买付费的证书。写这篇文章就是希望帮助那些希望使用云服务厂商免费证书的同学快速找到入口。
打开 console.aliyun.com 了,登录进入阿里云控制台。
在阿里云控制台找到 SSL 证书(应用安全)这个产品,点击进入产品控制台页面。




这部分需要注意的是:
当你配置完成后,稍等片刻,证书就会生成成功,此时点击操作栏的「下载」即可下载到证书文件,你根据自己的实际情况,下载对应格式的证书即可。

虽然阿里云的免费证书一年只有 20 个证书的名额,但对于绝大多数人来说,已经足够,在你需要 CDN 或其他更新不方便的情况下,使用云厂商提供的免费一年证书还是挺好的。

在开发 WordPress 主题时,我们会用到一些全局方法,来帮助我们快速加载特定的区域的代码。如果我们在设计和开发主题的时候,也可以实现类似的功能,则在开发对应的页面和应用的时候,我们就可以根据自己的需求来进行特定区域的代码的封装。这样我们在进行后续的开发的时候,就可以简化自己的代码,同时还可以按照 WordPress 的规范提前拆分代码,在实际进行项目开发的时候,提升效率。
本次实现主要是基于 Pug 自带的 Mixins 机制来实现在主题中提供自定义的函数,从而实现我们想要的内容。在原理上,和 WordPress 的 get_sidebar 之类的方法不完全一样。所以,在体验上还没有做到像 WordPress 那么方便。
在项目的根目录下创建一个 mixins 目录,并在其中创建一个 includes.pug 文件和一个 getHeader.pug 文件。
在 includes.pug 文件中添加如下代码
include getHeader
Code language: PHP (php)在 getHeader.pug 文件中添加如下代码
mixin getHeader
p header
在你的 layouts.pug 文件中加入 includes.pug 的引入。需要注意的是,要加在 doctype 之前。
include ../mixins/includes
doctype html
html
head
Code language: PHP (php)当你完成上述的配置后,即可在需要的地方进行调用。
extends layout
block content
+getHeader
h1= title
p hi to #{title}
Code language: PHP (php)调用的效果如下:

如果你希望实现更加强大的功能(比如参数),可以参考 Pug 官网的 Mixins 页面。

我最近在准备开发新的 WordPress 的主题的工具,为了方便自己开发主题,正在准备一个脚手架,本文是开发过程中的经验总结。
白宦成
在进行主题开发的时候,一个很好的体验是来自于变更能够实时生效。过去我们想要实现这样的功能需要自己手动刷新浏览器。但随着前端技术的进步,我们可以借助诸如 browser-sync 这样的工具来完成自动的刷新,从而实现无需手动刷新,代码修改后自动刷新。此外,除了 browser-sync, 你还可以选择 webpack-dev-server。
此类工具的工作模式是比较简单的,一般而言,会要求你设定一个代理的端口,他会将对应端口的请求进行转发,并在其中加入 BrowserSync 的 JS 文件,从而实现可以无需手动操作来刷新。

而其刷新的能力则是源自于 BrowserSync 本地提供的 WebSocket Server。嵌入的 JS 文件中加入了 WebSocket 的相关链接代码, 从而实现从 Command Line 当中获取刷新指令,前端则在获取到指令后进行刷新。

首先在项目中引入 browser-sync ,执行如下命令
npm install browser-sync --save-dev
我是使用 express generator 生成的项目,需要修改 bin/www 文件,如果你是自己建设的项目,则需要自行修改。
在启动文件中找到监听端口的代码, 并在其回调函数中添加如下代码
# 添加前
server.listen(port)
# 添加后
var bs = require('browser-sync').create();
server.listen(port, () => {
bs.init({
open: false,
ui: false,
notify: false,
proxy: 'localhost:' + port,
files: ['./views/**', './routes/**'],
port: 8080
});
});
Code language: PHP (php)上述配置中,可以根据你的需要修改 proxy 、files、port 等选项,实现自定义配置。
关于配置的更多信息,你可以参考 https://browsersync.io/docs/options
在命令行中执行 npm start ,在浏览器中打开对应的页面,当可以看到内容后,可以修改文件,等待页面的自动刷新,如果成功刷新了,则表示你已经完成了相关能力的配置。