分类
分享

喜获思否 Top Writer

(其实年前就发给我了,现在才想起来拍照发……)

2020年,书没有写完,视频也没录完,不过花了很多时间在思否上答题。基本上从年初坚持到年尾,每天至少回答一个问题,能够占据着年度排行榜的一个位置。国庆后工作压力增大,没能坚持住,慢慢掉出排行榜。

幸运的是最终得到思否的认可,获评问答版 2020 Top Writer。感谢思否赋予我这项荣誉,也感谢思否赠送卫衣一件。

(去年坚持锻炼还是有效果的,开始我还担心 3XL 的卫衣会穿不上,没想到还挺合身。)

不过今年可能很难再接再厉了,答题很消耗能量,不是不会答,主要是没有好问题。更有不少鸡贼提问者,先提出问题,等待别人回答,自己验证通过,然后自己答一遍,再把自己选择为最佳答案,骗取声望。

今年打算多输出主观、成体系的内容,播客、视频、项目、书。短期计划先做直播,争取能收获一些稳定的观众群体,把小课堂群扩一扩,这样将来做什么都方便。跟同学们讨论了一下,从斗鱼迁到 了 B 站。作严肃内容的话,B 站的确比斗鱼更合适,对小主播也更友好。

总之吧,今年我厂有希望宏图大展,希望我自己也能在内容领域取得一些新的进展。

分类
招聘

代友招聘:每日优鲜 BI 高级前端

有个关系很好的朋友在每日优鲜负责 BI 系统,现在需要 一名 高级前端开发。

薪资范围:看能力,16个月,股票期权看级别

工作地点:北京望京南

岗位描述:

  1. 负责数据开发平台的前端架构和研发
  2. 参与智能分析平台的前端架构和研发
  3. 通过沉淀和抽象业务场景,打造低代码研发环境及工程落地

岗位要求:

  1. 本科以上学历,计算机相关专业
  2. 熟练掌握JavaScript,CSS,HTML等前端技术
  3. 至少深度用过一种主流前端框架( React \ Vue \ Angular等),并深入理解其设计原理
  4. 熟悉数据可视化经验优先,熟悉低代码技术者优先
  5. 主动、皮实、乐观、有担当,逻辑分析和解决问题能力强
  6. 良好的学习能力和团队合作意识,有技术追求,乐于分享

有意者请直接跟我联系,我初审后内推。

分类
分享

GitChat 的问题

目前来看,GitChat(gitbook.cn,简称 GC) 已经黄了。网站还在,但是已经基本没人运营。我认识的主创人员也都走了,所以把之前想吐没吐的槽吐一下吧。

0. 起高楼

我跟 GC 结缘较早。基本上,刚好在我投身知识付费领域的时候,GitChat 创办,然后我就加入做了一场:《第一场 GitChat 总结》。

坦率地说,当时我对 GitChat 的印象不错,主要有三个原因:

  1. 采用众筹模式,创作者在开始创作之前就已经对用户需求、用户反馈有一些准备,分享更加有的放矢。尤其对于我这种选题偏门的人来说,很有参考价值。
  2. 文字内容有利于检索。相对于其它网站的视频课程,文字内容可以被更多人找到(如果网站主允许的话,GC 实际上不允许,搜索只能搜到简介)。
  3. 每场 Chat 的最后一个环节,GC 会把订阅者和作者拉到一个群里进行交流。我非常喜欢这个环节,可以交流很多内容,还能获得一个关系群。(可惜的是,交流完之后他们就会把群解散。)

我觉得,GC 很好地填补了技术分享领域的一块空白:中篇收费文章,一次性说清楚一件事,不贪多:

  1. 比短文(例如我的博客)更系统、更完整、更有参考价值。很多时候你很难靠一篇博客完成一项任务,需要多看多试;而长文可以。拿来当参考书很好用。
  2. 比书本更聚焦,阅读压力更小,可以利用碎片时间,稳定的学会一项技能、了解一个知识点。
  3. 文字内容方便检索,可以覆盖更多人群,利用搜索引擎流量。

主创人员很有想法,很熟悉行业,也很有执行力。GC 产品有不少值得称道的创新点,假以时日,凭借合适的市场补位,应该可以有所成就。

1. 宴宾客

接下来我在 GitChat 上创建了多次 Chat,还不断记录下一些 Chat idea,从我的博客可以看到:https://blog.meathill.com/?s=gitchat

GC 也不断拓展运营方向。首先增设专栏,即加长版 Chat,长度最长可以接近书本。接下来引入年卡,首充打折,¥512/年,可以看所有 Chat(能看多少专栏我不太记得了)。对了,还有严选,即品质比较好的文章,可以有区别于普通文章的标记,相当于平台为作品背书,可以卖得更好。

专栏的竞品不少,掘金也在做,而且投入的资源更多;传统图书虽然不挣钱,但是品级高,所以大家也都愿意做。年卡价格其实不贵,Chat 定价多半在 10~20之间,512 相当于能看 50 篇高质量的长文,即使暂时用不上,也可以先加到已购里,等需要的时候在看。

后来,GC 出了一篇爆款,好像叫《Java 200 道面试题全解析》,卖出了 1w+。我感觉,很多变形操作就是从这篇爆款面世后出现的……

2. 楼塌了

在爆款之前,GC 存在的最大问题就是内容稂莠不齐。跟其它平台比起来,GC 是行业新人,缺少积累,所以作者门槛设得比较低。有些作者甚至对自己写的内容都搞不清楚;有些作者文笔很差,前言不搭后语;有些作者会在用户群里发盗版资源,拉人头报名自己的 Chat……

GC 团队似乎没有什么特别好的办法,只好推出“严选”标签,帮好文章背书。但是 GC 是专业平台,编辑本身对技术不是很在行,所以严选标签的选择也一言难尽……

这个问题随着爆款出现变得更加严重。爆款有成瘾性,不仅对作者,对平台更是如此。从《200+ Java 面试题》之后,普通作者的生存环境更加严酷。一方面,混杂其中的低端垃圾文拉低了整个平台的质量,付费阅读很少,大部分都是年卡会员打卡,分成很少。另一方面,平台不断把有限的资源投入到推广爆款文章和“看起来像”爆款文章的文章里面,一时间,“面试题”与“面试技巧”齐飞,“进大厂”共“快拿 offer”一色。普通作者(就是我)的文章更难出头,甚至连想加“严选”都要跟编辑反复沟通。

而普通作者的微信群沟通更是直接被取消了。

于是,我的创作欲望越来越低;别的作者也是如此,微信群也越来越沉寂。终于有一天,有个作者问:“GitChat 是不是黄了?”没人回答,可能真的是黄了吧。

3. 总结

在我看来,GitChat 初期的产品定位有独到之处,产品形态也做得不错。但是运营时遇到两个问题:

  1. 作者能力良莠不齐,作品质量参差不齐。为了降低读者购买的决策成本,加设年卡;结果又降低了作者的收益,进而降低了创作热情。
  2. (可能)由于资金压力和流量成本,片面追求爆款。导致平台上一时间充斥着各种无营养的面试文,损害了真正知识获取者的体验。

当然,吐槽容易,解决问题很难。即使假设大家都现金购买,我一篇文章也不过几百块,完全覆盖不了我写文章的成本。所以,搭建一个作者愿意写,读者愿意花钱看的中篇平台,还有编辑负责内容审核和读者群搭建,这个商业模式是否真的成立,我也说不准。

不过,我真的希望有个这样的长文平台,希望将来会有。

分类
css

重发老视频:使用 CSS 制作工序流程图

整理之前录的视频,发现一个漏掉没有上传的:

这个视频里,我演示了如何使用纯 HTML + CSS 制作工序流程图。涉及到的技术包括:

  1. display:flex Flex 布局
  2. 使用 order: N 调整显示顺序,以实现响应式
  3. 使用 position:XX 调整定位

虽然项目不大,不过大部分布局相关的技术都有所涉及,很适合刚入门和初级同学学习。


今年想继续在直播、视频方面发力,希望大家支持。如果有什么想听的想看的想学的,也欢迎点菜。

分类
前端工具链

Tailwind.css + Postcss 笔记

0. 缘由

去年,一篇《Tailwind CSS: From Side-Project Byproduct to Multi-Million Dollar Business》在我的时间线上刷屏,作为 side project 和自由职业的翘楚,他的产品和商业项目十分令人羡慕。

所以,我一直想找个机会试用一下 Tailwind.css。这次春节,想着放松休闲一下,就开了个小项目,尝试一下新技术栈:

  1. Vue3 全家桶
  2. Tailwind.css + PostCSS
  3. Webpack 工具链

这篇笔记用来记录心得和体会。


1. 基础

官方网站:https://tailwindcss.com/

2. 安装&配置

npm install tailwindcss@latest postcss@latest autoprefixer@latest
// postcss.config.js
module.exports = {
   plugins: {
     tailwindcss: {},
     autoprefixer: {},
   }
}

2.1 创建 tailwindcss 配置

npx tailwindcss init

生成的配置文件如下:

// tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}

2.2 创建 CSS

@tailwind base;
@tailwind components;
@tailwind utilities;

这个 CSS 无法直接被浏览器使用,需要经过 PostCSS 调用 Tailwind 插件编译后才行。

2.3 配置 Webpack

只需要配置 CSS 和 Stylus 规则:

module.exports = {
  module: {
    rules: [
      {
         test: /.css$/,
         use: [
           isDevServer ? 'style-loader' : MiniCssExtractPlugin.loader,
           'css-loader',
           'postcss-loader'
         ]
       },
       {
         test: /.styl(us)?$/,
         use: [
           isDevServer ? 'style-loader' : MiniCssExtractPlugin.loader,
           'css-loader',
           'postcss-loader',
           'stylus-loader',
         ],
       },
    ]
  }
}

2.4 配置 .browserslistrc

PostCSS 同样需要用 browserslist 处理兼容性问题,所以一定要配置好,比如我近期喜欢用 bootstrap-icons 为图标,需要用到 svg-mask 系列属性,在 Chrome 里就需要补充前缀。那么,如果 browserslist 里没有 Chrome 就不会加前缀(我昨天就踩在这个坑里)。可以使用 npx browserslist 来检查。

2.5 修改 npm scripts

PostCSS 和 Tailwind.css 需要用 NODE_ENV 变量决定动作内容,所以必须加到 npm scripts 里。

{
  "scripts": {
    "serve": "NODE_ENV=development webpack serve --config build/webpack.config.js",
    "build": "NODE_ENV=production webpack --config build/webpack.config.prod.js --mode=production",
    "lint": "eslint --fix --ext=.vue,.js ./"
  }
}

2.6 完成

至此,基础 Tailwind.css + PostCSS + Webpack 配置完成,接下来就可以使用 CSS 实现界面了。

分类
职业

好书推荐《重构(第二版)》

前些天偶然看到,《重构》发了第二版,而且是以 JavaScript 作为范例语言编写的。于是我马上买了一本,翻了一遍,还是熟悉的好味道。在这里推荐给大家。

点击这里购买 。年前京东半价,现在稍微贵一些,大家可以等一等,或者自己凑凑单。

也可以扫码购买:

0. 我的编程启蒙

我的编程技能是自学的。最初就是看一些少儿科普图书,上面会教些计算机基础知识,和 Basic 编程。所以很长一段时间里,我都只会在 BASIC 开发环境下执行程序,而对如何让代码在任意环境下执行一无所知,这严重限制了我编程能力的覆盖范围。

幸运的是,等到我考上大学,正值第一波互联网泡沫破灭,Web 开发风生水起,Flash 蒸蒸日上,所以,只要会写代码,就有地方能跑,而且是一个大平台。有赖于此,我的编程能力可以稳步提升。

1. 《重构》(第一版)

但一直自学,缺少交流和指引,也大大限制了我的编程能力的发展。站在当时的角度,我并不觉得有什么问题;但是现在,我回顾自己的职业生涯,觉得那其实是很大的危机。如果就这么抹黑自学,毕业后以非科班的身份去社招,多半会陷入很多转行同学一样的尴尬境地。

幸运的是,我无意中买到《重构》这本书,并且看完了。这本书极大的开阔了我的视野,告诉我什么才是真正的编程、什么样的代码能事半功倍,以及除了完成业务之外,编程还有哪些工作。

于是,我不仅在日后的开发工作中取得重大突破(幼儿园全 Flash 官网),在未来的招聘面试里也能够脱颖而出,顺利入行。

以前的一篇博客里,我把《重构》列为对我职业生涯影响最大的书。

2. 《重构(第二版)》

相比于第一版,《重构(第二版)》又有两个比较大的改进:

  1. 产品类型升级,改成了大家更熟悉的电商订票网站
  2. 使用 JavaScript 重构代码,更适合现代前端程序员阅读

对于广大靠前端开发维生,或者想靠前端开发维生的同学来说,这本书能极大的提升你的工作能力,让你未来的工作事半功倍。对于那些跟我一样靠自学、半路出家的非科班程序员,这本书就更加重要了,它能告诉你什么样的代码才是好代码,怎样写出更好的代码,以及该怎么写合适的代码。


总之,推荐给大家。如果能使用我的 推广链接 就更好了。

分类
前端工具链

升级 Webpack 4 至 Webpack 5 笔记

Webpack 5 已经发布一段时间了,我也找机会把几个项目从 Webpack 4 升级到 Webpack 5,从中积累了一些经验和教训,记录于本文。

0. 请先阅读官方升级指引

链接在此:To v5 from v4。(其实我也没认真读完……)

0.1 @vue/cli 不要贸然升级

@vue/cli 目前的版本号是 4.x,使用它创建的项目需要 webpack 4,升级到 Webpack 5 的话,因为两个版本配置文件存在差异,就无法正常使用了。所以如果是 @vue/cli 创建的项目,就不要贸然升级。

1. 升级依赖

随着 Webpack 一起升级的,还有 webpack-cli、webpack-bundle-analyzer、webpack-dev-server;以及一众插件,比如 html-webpack-plugin、terser-webpack-plugin 等。

因为存在依赖关系,建议大家一起升级:

# 检查新版本
npm outdated

# 安装新版本的 webpack 套件
npm i webpack@5 webpack-cli@4 webpack-dev-server@3

2. 升级配置文件

大部分配置可以直接继续使用。

3. 升级 npm scripts

Webpack 5 对内部模块的使用有所调整,所以我们需要调整一下 npm scripts。

3.1 webpack-dev-server

# 仍然需要安装 webpack-dev-server
npm i webpack-dev-server -D

# webpack 4
webpack-dev-server --config build/webpack.config.dev.js

# webpack 5
webpack serve --config build/webpack.config.dev.js

3.2 webpack-bundle-analyzer

# 仍然需要安装 webpack-bundle-analyzer
npm i webpack-bundle-analyzer -D

# webpack 5
webpack --analyze --config build/webpack.config.js

# webpack 4,配置 build/webpack.config.js 实现

4. 问题&解决

4.1 解决:`Can’t resolve ‘http’ in ‘axios’

在一个项目中,因为需要针对不同浏览器进行不同的适配,所以我们给 .browserslist 加入了环境配置:

[modern]
last 5 chrome versions
last 3 firefox versions
last 2 safari versions
 
[withie]
last 5 chrome versions
last 3 firefox versions
last 2 safari versions
edge >= 18

然后编译时就会报这个错误:

Can't resolve 'http' in 'axios'

经过一段时间的 Google,发现给 webpack.config.js 添加 target: 'web' 可解。所以我猜测,是因为我们的 .browserslist 有环境配置,所以 webpack 没认出来,所以当作 node 来打包。

在 Webpack 4 时期,Webpack 自带 polyfill,所以没什么问题;但是 Webpack 5 把这个 polyfill 移除了,所以就报错。

4.2 解决 HMR(自动更新,热模块更新,hot module reload)失效的问题

使用 Webpack 5 后,有些项目的自动更新会失效,这是因为 Webpack 没有正确的识别项目的执行环境,错把它当成 node.js。这个时候,在 package.json 里添加 target: web' 即可解决。

分类
技术

欢迎欢迎

欢迎来到我的博客,我是 Meathill,想了解我可以点 关于我

我每周一至五,晚上9:00~10:00 会在 B 站直播,https://live.bilibili.com/5126601,一般会跟代码相关,感兴趣有时间的同学可以关注下。

最近我在 @Easy 的课兔平台上众筹课程《从知名仓库学习设计模式》,恳请大家支持。

课程二维码:

众筹失败的话,会全额返还购课款,请放心购买。

分类
js

Webpack 不支持 `import.meta`,利用 ESM 在浏览器里使用 yargs

前些天遇到一个需求:解析 curl 请求,并转换成 ajax 请求由浏览器发出去。

我觉得这个需求听起来不算稀罕,理论上应该有现成的库。于是在 npm 找了一下,发现 curlconverter 似乎可以满足需求。但是使用的时候报错:Module parse failed: Unexpected token

这个错误很奇怪,看起来像是 loader 没配好。打开报错的文件位置,怎么看语法都没问题。尝试修改 webpack 配置,也未果。因为项目是 vue-cli 创建的,在如何查看最终配置上也浪费很多时间。

最后继续诉诸 Google,关键词换来换去,终于在搜索 mjs Module parse failed: Unexpected token 时找到这个 issue:https://github.com/arnog/mathlive/issues/525,继而找到 https://github.com/webpack/webpack/issues/6719,终于确定,这是 webpack 的问题。

因为 webpack 不支持 import.meta,所以会把 import.meta 当成语法错报告。我觉得这个行为很扯,因为 loader 配错也会报这个,所以对于第一次接触到这个问题的开发者(比如我)而言,会浪费大量时间在那些初级错误的搜索结果里。

接下来解决问题。

curlconverter 虽然不能直接使用,但仔细阅读它的代码,其中 https://github.com/NickCarneiro/curlconverter/blob/master/util.js 解析 curl 命令的功能实现应该问题不大,我只要想办法把 yargs 加载进来即可。而 yargs 支持浏览器 ESM 加载,所以我在页面里添加了 <script type="module" src="./yargs.js">,使用如下代码:

// 虽然 yargs 已经到 16.2,但是 16.0.4 之后的版本都有问题
import Yargs from 'https://unpkg.com/yargs@16.0.3/browser.mjs';

// 加载完成 yargs 之后,把它挂载到 window 上
window.Yargs = Yargs;

将 yargs 挂到 window 上,成为外部库。然后在 vue.config.js 里配置 externals:

module.exports = {
  chainWebpack: config => {
    config.externals.yargs = 'commonjs Yargs';
  }
}

接下来,将前面说的 utils.js 复制到本地并修改其中 parseCurlCommand 的实现,最终完成了需求。


总结一下:

  1. 使用 yargs 解析命令行请求比较方便,远比自己写方便
  2. yargs 无法配合 webpack,据说可以配合 rollup 或者 snowpack,在我的 vue-cli 项目中,需要使用一些特殊的手段加载
  3. curlconverter 也很好用,可惜不能直接用
分类
OpenResty

我的第一段 OpenResty 代码

前端同学需要一个上传文件的后端做一些调试,我刚好有,就给她用了。然后遇到跨域问题,一般来说我会在 PHP 里解决,不过这次我想挑战一下 nginx,于是找到这个答案。照做之后,OPTIONS 请求按照预期返回了正确的头,但是 POST 不行。

于是我在群里请教同事,结果被老板批评:

  1. 在 nginx 里,“IF is evil”,因为要在一些特定条件下,它的行为会跟预期完全相反;有时候甚至会引起 segfault
  2. 我厂是 OpenResty,没理由不用 OpenResty

行吧,本来就是为了跨出舒适区,不妨走远一点,OpenResty 就 OpenResty。

0. 用 OpenResty 替换 Nginx

我的系统是 Ubuntu 18.04,所以先按照 官方文档 安装最新版本的 OpenResty。

安装完成之后,可以通过 service --status-all 查看服务列表,不出意外的话,能看到 openresty 服务。

停掉 nginx,然后启动 openresty:

service nginx stop
service openresty start

此时 openresty 的配置位于 /usr/local/openresty/nginx/conf/nginx.conf,默认的 web 服务地址是 /usr/local/openresty/nginx/html/,所以我们需要修改一下,以便继续使用 /var/www/html,也就是之前 nginx 的网页文件。

1. 继续使用 nginx 的配置

修改配置的方式很简单,OpenResty 本来也兼容 nginx 的配置。对于我而言,最简单的做法是干掉 server 的部分,然后加载 nginx 的网站配置,也就是这两句:

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

此处会有个小问题:PHP 网站的配置里需要加载 snippets/astcgi-php.conf,默认使用的是相对路径,需要改成绝对路径 /etc/nginx/snippets/fastcgi-php.conf

至于其它配置,比如 gzipssl 等,酌情拷过来即可。

2. 增加配置以自动输出请求头

最后就是写 lua,这部分难度不大,基本就是普通的 lua 和 nginx lua API。写好的配置是这样的:

location / {
  access_by_lua_block {
    if ngx.req.get_method() == 'POST' then
      ngx.header['Access-Control-Allow-Origin'] = '*';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Allow-Expose-Headers'] = 'Content-Length,Content-Range';
 
    elseif ngx.req.get_method() == 'OPTIONS' then
      ngx.header['Access-Control-Allow-Origin'] = '*';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Max-Age'] = 1728000;
      ngx.header['Content-Type'] = 'text/plain; charset=utf-8';
      return 204;
    end
  }
  # First attempt to serve request as file, then
  # as directory, then fall back to displaying a 404.
  try_files $uri $uri/ /index.php$args;
}

首先,使用 access_by_lua_block 添加 lua 代码块。这里注意,一定要用 access_by_lua_block,不能用 content_by_lua_block,因为我们后面还要用 proxy_pass 把请求反向代理给 php-fpm 处理,而 content_by_lua_block 就直接返回了。

然后,因为要添加 headers,所以要在能输出其它内容前先输出头。所以这个代码块要放在最前面,前面不能有其它输出。

3. 总结

需求不大,代码也比较简单,不过还是花了大约一天的时间调试。将来可能会写更多的 OpenResty lua,到时候再慢慢分享咯。

另外我也搞不清楚为啥 nginx 这么流行的一个软件竟然有 if 这种问题。有知道的同学请指教。