用babel插件将现有项目硬编码中文自动国际化

背景 前段时间接手了一个祖传项目,现在因业务需求,需要对产品进行国际化。 这个工作说起来也简单,但是就是个体力活啊,再说了,花费这么多时间对自己的成长可以一点用也没有啊,万一后面还有其它项目,需要做类似的工作呢,咱这次对下一次可是一点帮助也没有啊,这完全不符合我推崇的可迭加的进步啊。 想到自己之前也接触过AST和babel,看过神说要有光(公号「神光的编程秘籍」)的掘金小册《Babel 插件通关秘籍》,虽然里面的做法不太符合我的项目,但是拿来参考借鉴是足够的,网上搜了搜现成的解决方案,没找到实用的,只能自己动手干起来了,这也不失为一个很好的练习契机嘛。这个项目其实最近一年的新代码已经接入i18n了,但是历史旧账更多,没人愿意动,这次就让我练手吧。 我们的宗旨是尽可能做到用代码解决问题,尽可能地减少人工干预。 提取待翻译中文 首先我们需要先把代码已经硬编码的中文识别出来,这样才能给产品拿去翻译(或者调用翻译api来翻译),怎么识别呢,我们需要通过正则表达式来实现。 /[^\x00-\xff]/能够识别双字节字符,我们可以借助它来判断,我们平时用到的中文标点符号也是。 我们在编辑器里面用这个正则表达式就能搜到项目里面有多少中文,/[^\x00-\xff]/其实检测的不只是中文,准确来说叫非英文,后面我们还是简单点直接叫中文吧。 AST 代码里面这么多中文,我们怎么知道它们是什么呢,这就需要用到AST(抽象语法树)了。我们可以借助https://astexplorer.net/ 来查看了。AST的基础知识需要读者自行查阅资料学习了。 我们可以搞一点代码测试下 import React from 'react'; // 多语言 import { IntlProvider, addLocaleData } from 'react-intl' function Test(props) { console.log("abc", "你好"); const data = { value: "文本" } const abc = "ctx" + data.value + "嗯"; const efg = Read more…

CKEditor系列(七)编辑器工具栏根据宽度自动折叠

刚才看了看上一篇写CKEditor的文章是在今年的一月份,现在轮到我们的设计师对编辑器下手了。我们回顾下现在的编辑器长什么样子。 需求 我们客户端默认窗口尺寸下,会出现排,并且第二排的这些功能使用频次相对较低,为了尽可能的增大用户的操作区域,所以决定做如下改动: 将居左对齐、居中对齐、居右对齐改成三合一的功能 将频次使用率低的有序列表和无序列表调整至最后面 根据可用宽度收起一行展示不下的工具栏图标 有这个需求,经验告诉我官方大概率不会有这种配置,但是还是先去官网和Google上搜搜吧。 最终发现官方有个toolbarCanCollapse配置项,虽然有个折叠按钮的功能,但是远远不能满足需求。 对齐三合一功能更不可能有了,也没有找到。 效果 我们可以提前看下本文最后的实现效果是什么样的 CKEditor工具栏实现原理 # toolbar/plugin.js editor.on( 'uiSpace', function( event ) { if ( event.data.space != editor.config.toolbarLocation ) return; // Create toolbar only once. event.removeListener(); editor.toolbox = new toolbox(); … var toolbars = editor.toolbox.toolbars, toolbar = getToolbarConfig( editor ), toolbarLength = toolbar.length; Read more…

Mac切换终端至Oh My Zsh后,保留原/bin/bash终端显示名

原生终端 也就是使用的是/bin/bash \h表示本地主机名 \W表示当前目录 比如~ \u表示用户名 $表示符号$ 写在~/.bash_profile即可 个人不喜欢显示本地主机名,感觉太长了,也没什么用。显示出用户名和当前目录就可以了 cd ~ vi .bash_profile // 写入 PS1='\u:\W \$ ' source .bash_profile 其中PS1变量,这是用来定义终端提示符的。 Oh my zsh 现在很多人用的 这个了,Mac的默认终端也改成/bash/zsh 今天第一次使用Oh my zsh,然后发现终端前面的前缀变了。。。 这不是就是将我的设置变量直接给原样输出了吗。 在网上搜了下,各种雷同和眼花缭乱的设置,我简答总结下 把自己zsh当前使用的主题复制一份,改成自己的自定义主题,方便后续升级时不受影响 查看当前使用的zsh主题 cat ~/.zshrc 复制当前zsh主题,并修改 截图的地方就是当前使用主题,我的已经复制过了,从robbyrussell复制到custom下。 cp ~/.oh-my-zsh/themes/robbyrussell.zsh-theme ~/.oh-my-zsh/custom/themes/myrobbyrussell.zsh-theme vi ~/.oh-my-zsh/custom/themes/myrobbyrussell.zsh-theme 在zsh中使用自己修改过后的主题 cat vi ~/.zshrc source vi ~/.zshrc 具体code的参照表 Read more…

深入学习React时间切片,任务调度scheduler

背景 最近想起月初看到的魔术师卡颂(微信号:kasong999)的一个公开直播——《手写React优先级调度算法》,虽然我更倾向于认为直播内容是演示如何利用React官方同款调度库手写代码了解优先级调度,但是这并不影响我对直播内容的高质量的认可。 直播UP主魔术师卡颂给出的完整demo代码可以在https://codesandbox.io/s/xenodochial-alex-db74g?file=/src/index.ts中看到 执行效果如下 点击按钮生成的新任务,先将该任务放入到任务队列进行调度,然后选出最高优先级的先执行,在执行的过程中,如果发现有更高优先级的新任务(点击等其它操作生成的)插入进来,继续选出高优先级任务先执行,待当前最高优先级任务执行完毕后,继续在队列中选中剩下的最高优先级的执行,如此往复,直至队列任务全部执行完毕。 总体的执行流程就是:onclick加入任务 -> schedule -> perform -> schedule -> perform … 演示代码 完整代码如下: // index.ts import { unstable_IdlePriority as IdlePriority, unstable_ImmediatePriority as ImmediatePriority, unstable_LowPriority as LowPriority, unstable_NormalPriority as NormalPriority, unstable_UserBlockingPriority as UserBlockingPriority, unstable_getFirstCallbackNode as getFirstCallbackNode, unstable_scheduleCallback as scheduleCallback, unstable_shouldYield as shouldYield, unstable_cancelCallback as cancelCallback, CallbackNode } Read more…

打开网页或调用接口时Chrome报错ERR_HTTP2_PROTOCOL_ERROR解决方案

少数情况因为网站使用http2配置不当,导致网站打开不正常,Chrome报错ERR_HTTP2_PROTOCOL_ERROR 有的时候我们在调用接口的时候也会出现这类问题,接口一直显示pending最后超时,在控制台能够看到报错信息 我们在无法定位并从源头解决问题的时候,可以通过自行调整客户端 Chrome的配置来解决问题。 步骤如下 打开chrome://flags/ 页面 Ctrl+F搜索找到Block insecure private network requests和Enable Trust Tokens两项 将其值从 Default 改为 Enable 点右下角的 ReLaunch 按钮重启浏览器 重新打开报错的网站 如果打不开,在地址栏输入 chrome://restart/ 再重启一遍浏览器即可 操作步骤源自 一只小茉莉的Chrome“ERR_HTTP2_PROTOCOL_ERROR”解决

回顾下跨域解决方案http-proxy-middleware

我们在React(或Vue)项目本地开发过程中很容易由前端自己解决跨域问题,这里面就用到的是插件http-proxy-middleware,它并不是webpack独享的插件,而是一个通用插件,它对http-proxy进行了一层封装,更加方便我们使用。 之前刚接触webpack的时候写过一个webpack反向代理proxyTable设置 前几天有个测试同事找我解决她的跑的本地项目测试公司项目时,出现跨域的情况,因为前端项目不是spa项目,没有webpack之类的,所以就准备参照http-proxy-middleware来实现。 我们看看http-proxy-middleware的源码,目前它的最新版本是2.0.6,貌似2.x版本和1.x版本导出的方法有所不同 先看看npm官网的示例介绍 const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true })); app.listen(3000); 我们只是想在自己的express项目使用http-proxy-middleware,那就可以到此为止了,如果想继续了解http-proxy-middleware,我们就需要往下看这个createProxyMiddleware方法。 // node_modules/http-proxy-middleware/dist/index.js const http_proxy_middleware_1 = require("./http-proxy-middleware"); function createProxyMiddleware(context, options) { const { middleware } = new http_proxy_middleware_1.HttpProxyMiddleware(context, options); return middleware; } exports.createProxyMiddleware Read more…

spa前端 + wordpress后台项目配置nginx实战和静态资源配置难点

现在将wordpress作为后台项目,自己用vue或者react做自己的前端的项目越来越多,虽然作为同一个对外的项目,实际上是有两个项目组成,那怎么去分配这两个项目的路由呢?哪部分走spa,哪部分走wordpress呢? 链接分析 .php链接 wordpress是一个php项目,所有php的路由必然需要交由wordpress(php)处理 location ~* \.php$ { root /home/website/wordpress; fastcgi_pass unix:/usr/local/php/var/run/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; index index.html index.php; if (-f $request_filename/index.html){ rewrite (.*) $1/index.html break; } if (-f $request_filename/index.php){ rewrite (.*) $1/index.php; } if (!-f $request_filename){ rewrite (.*) /index.php; } } 内容相关链接 这部分是spa项目实现的核心部分了,一般是首页,列表页(分页、标签、日期等),内容详情页 location ~* ^\/($|(category|tag|date|page)\/|\d+\.html$) Read more…

Google Adsense,回来了

我在这几天的集中隔离期间又思考下睡后收入,也就是被动收入,这些是我们自己不用花费多少时间和精力,就可以自动获得的收入,这部分收入的数量已经在我们总收入的占比越大我们越自由。 我查了查当初停掉网站的Google Adsense的时间是在2020年的6月底,停掉的原因很简单,就是因为当时的主机访问速度比较慢,首次打开的速度不太理想,为了国外Adsense拖速度就停了,不知不觉停了快两年了啊,时间过的真快。 自从2021年11月开始使用腾讯云主机之后,访问速度一直很可观,比2010双十二之后的阿里云,以及之前的的搬瓦工速度快到了。今天4月份也把网站的PWA优化过,缓存用的也是六六的,老用户访问速度更是快。 Google Adsense的自动广告位置还是合理,后台可以配置禁用哪些类别的广告推送,可以说对访问者算是友好的了。 总结一下重新开启Google Adsense的原因有三点 睡后收入 网站速度大幅提升,Google Adsense不会拖速度了 Goolge Adsense广告优化 昨天晚上已经开始着手激活了,但是生效没那么快。 因为历史原因,我的Google Adsense一直是在用之前的Google账号上面,那个账号其它东西要么转移,要么废弃,就剩下Google Adsense了,昨天意外发现Google Adsense其实是可以添加管理用户了,可以让多个Google账户管理同一个Google Adsense。 早知道能这样,我就不用每次因为要开隐私模式登录Google Adsense而不愿意登了,真是个好消息,解决了多年的心病啊。 我果断添加上我现在的常用Google账号,然后把之前的账号直接给删了,这就是妥妥的“资产”转移啊。哈哈😄😄 我手痒在Google上搜了下,这个早就有了。。。 差不多十年前就有这个功能了,扎心了。。。 2012年,我当时应该还在用的老账户吧,感谢产研团队前辈们啊。我在启用新Google账号的时候都没想过会官方会支持这种功能,也没认真了解过各项设置。 两年,让我想到了海贼王里面的镜头。3D2Y,One piece。

网站接入OAuth 2.0扩展协议PKCE,获取access_token实战

在了解了OAuth2.0的扩展协议PKCE(细节可以在由Raycast to flomo了解到OAuth 2.0之PKCE中看到),我也想试试,尝试接入一把。 使用npm包oidc-provider,具体可以源码及文档https://github.com/panva/node-oidc-provider 配置 根据文档里面的example的express简单修改下。 修改 clients: [ { client_id: 'client_id', client_secret: 'client_secret', redirect_uris: ['http://127.0.0.1:3000/callback'], grant_types: ['refresh_token', 'authorization_code'], code_verifier: '2Ealc1zZfDjmm-RNct0U7POlQmj.-z9fFb2cuk4eZw_LyVZEMp2B.Uwl5t3RvX6RCovo7qkZdP6-HEh9-lQanPKrO_20j.7kyIzWc-7_Z3GB2HXmwCXkSflPh7AMJ59m', code_challenge: 'LVogXRp-NbtBYMm1ed88xNwvmuoanfBcbWoeKYzeOEU', } ], 配置上code_verifier 和对应的code_challenge , 我们可以直接在线生成 => pkce-generator 直接运行node example/express.js就可以开始调试了。 在http://localhost:3000/.well-known/openid-configuration 页面我们可以看到生效的配置和被oidc-provider接管的路由地址。 获取Authorization Code 浏览器访问 http://localhost:3000/auth?client_id=client_id&redirect_uri=http://localhost:3000/callback&response_type=code&code_challenge=LVogXRp-NbtBYMm1ed88xNwvmuoanfBcbWoeKYzeOEU&code_challenge_method=S256&scope=openid profile &nonce=123 &state=321 其中的code_challenge_method=S256别忘了。 如果未发现报错的话,会出现这样的界面 目前是没有校验登录名和密码的,随便输入即可。 点击“Sign-in”后 点击“Continue”后 我们可以看到已经跳转到我们之前填的redirect_uris地址,并且页面上也带上了code,这个就是authorization code。 Read more…

由Raycast to flomo了解到OAuth 2.0之PKCE

五一期间在flomo官网的扩展中心看到了这个Raycast to flomo,对Mac上的效率工具有了点了解,我直接基本都没有用过Mac自带的spotlight。。。 我好奇的不是竟然可以用这种方式发送到flomo,毕竟官网API摆在那,调一下也很简单,我惊奇的是Raycast跟Mac系统的风格比较搭配,看上去不错,就去Raycast的官网看了一下。 缘起 看了下Raycast的API文档,妥妥的对前端开发及其友好啊,大赞! 文档撸了一遍之后,我看到自己感兴趣的Auth部分。 用官网的demo试了试twitter的oauth pkce登录流程,很顺畅,瞬间有了一种想给道招网也安排上,虽然本站基本只有我一个人会登录,很多年前我就把注册功能给禁用了,这次准备开放了。 自己顺便了解了一下PKCE流程 上图来自auth0.com 原来PKCE是为了优化现在流行的SPA应用token验证流程的。 OAuth2.0 先回顾下OAuth2.0流程: 在获取token的时候需要提供如下信息: code redirect_url client_id, client secret 第二项和第三项其实是用来对通过code获取token的client的合法性进行验证。其中最核心的应该是client secret。通过它可以解决如下问题: 对获取token的client进行合法性验证。secret是在Authorization Server上注册client的时候设置的,只有client自己知道,因此可以对client进行验证。 这样的话,即使code因为某种原因泄露了,没有secret也无法获取到token。从而提升了安全性。在传统的Web应用中,token的获取是发生在后端,因此secret也是保存在后端。这样是可行的。但是对于现在比较流行的SPA应用,token的获取是发生在浏览器端,是一个公开的环境。这个方法就不可行了,因为secret不可能保存在一个公开的环境中。 PKCE PKCE主要是通过在授权的过程中增加了code_challenge和code_verifier两个元素来对整个流程进行验证,防止code被第三方截取的情况。具体流程如下: 这里面最核心的其实就是在authorize请求中增加了code_challenge参数,在token请求中增加了code_verifier参数。这两个参数最终都是依赖于一个client生成的随机字符串。 codeverifier:一个Client端生成的随机字符串(由字母,数字,- ,. , ,~ 组成) code_challenge:由code_verifier生成的字符串。 生成算法为:BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))。 过程解析: 在申请授权时(authorize请求),client将code_challenge传给authorization server.(这个过程中code_verifier在网络中不会被暴露,因为对其进行了hash)。 authorization server生成授权码后,会将code_challenge保存起来,并与授权码关联。 在通过授权码获取token的过程中,client会将code_verifier传给authorization server authorization server会将code_verifier按照第一步相同算法计算得到新的code_challenge authorization server将第四步计算得来的code_challenge与第一步中的原始code_challenge进行比较,如果相同则认为申请授权的源与用code获取token的源为同一来源。(即code没有被第三方截取而冒用) 客户端一般用oide-provider来对接PKCE。 参考文章 Authorization Code Read more…