Giter Site home page Giter Site logo

hzfe-questions-and-answers's Introduction

hzfe

hzfe website

Build Setup

# install dependencies
npm install

# serve with hot reload at localhost:8080
npm run dev

# build for production with minification
npm run build

# build for production and view the bundle analyzer report
npm run build --report

For a detailed explanation on how things work, check out the guide and docs for vue-loader.

hzfe-questions-and-answers's People

Contributors

akiq2016 avatar daryl-l avatar gongpeione avatar llawlight avatar stackjie avatar topeas avatar volvo18a avatar xiaokk06 avatar yiiu avatar yinmazuo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hzfe-questions-and-answers's Issues

BUG!从编写 Loader 到窥探大佬 Debug 全过程

原文:BUG!从编写 Loader 到窥探大佬 Debug 全过程

不同于 web 开发的 html + js + css,在原生小程序开发中,我们使用的是 wxml + js + wxss。web 开发中,我们常借助 webpack 的能力进行代码打包,小程序中同理可用。

今天我们的目标是编写一个真实可用的 wxml-loader,这个 loader 主要用于收集 wxml 中的本地资源,比如图片,然后就可以交由 file-loader 来进行文件的处理;以及支持输出压缩后的 wxml 文件,减少文件大小。

一、术语解释

  1. WXML 是小程序的一套标签语言,可类比于 HTML。
  2. AST 是抽象语法树(Abstract Syntax Tree)。
  3. sax 是可以用于 XML 和 HTML 的解析器。
  4. html-minifier 是基于 JavaScript 开发的 HTML 压缩工具

二、目标功能

收集 WXML 中的本地依赖,预期最终输出目录中,包含这些被引用的资源文件;

<image src="../img1.jpg"></image>

压缩 WXML 文件内容;

<!-- 输入 -->
<view>
123
</view>

<!-- 输出 -->
<view>123</view>

三、实现思路

收集依赖:获取到 WXML 字符串内容后,我们自然而然希望把他转换为 AST 进行分析,此处我们借助第三方工具 sax parser,通过解析后的数据,根据节点类型、属性类型匹配的情况,按需收集对应的本地资源地址。

// webpack 匹配到 wxml 后缀文件后
// 交由给当前 loader 处理
// content 参数获取 wxml 文件内容
function wxmlLoader(content) {
  let requests = [];
  const rootCtx = this.rootContext;
  const parser = sax.parser(
    false,
    { lowercase: true }
  );
  
  // ...

  // opened a tag. param: node
  parser.onopentag = function(n) {
    // 解析 node 节点内容进行
    // 本地资源收集 (getResource)
    // 然后调用 urlToRequest
    // 将资源 url 转为 webpack 模块请求
    requests = requests.concat(
      getResource(n).map((_) =>
        urlToRequest(_, rootCtx)
      )
    );
  };

  parser
    .write(`<R>${content}</R>`)
    .close();
};

压缩文件:此处可以直接使用第三方工具 html-minifier 。

function wxmlLoader(content) {
  const callback = this.async();
  const minimizeOpt = { /** */ };

  // ...

  // 在parser流结束时 
  // 进行 content 最后的处理
  parser.onend = async function() {
    try {
      // ...
      if (minimizeOpt) {
        content = HTMLMinifier
          .minify(
            content,
            minimizeOpt
          );
      }
      callback(null, content);
    } catch (error) {
      callback(error, content);
    }
  };
}

四、实战踩坑

以上,我们的 wxml-loader 的核心功能就完成了(不好意思,省略了很多代码)。放入我们的实际开发中项目进行验证测试。

Bug1

实践出真实,遇到了 Parse Error 的报错:

<view>
  500元≤累积业绩{{'<'}}1000元
</view>

在小程序中,可以用 {{变量名}} 这样的插值表达式来绑定 WXML 文件和对应的 JavaScript 文件中的 data 对象属性。

而对于 html-minifier 而言,这个语法只是普通的字符串内容,在解析到 {{'<'}} 中的 < 时,会被理解为标签的开头,因此报了 Parse Error 的错。

为减少对已有项目的内容改动,选择了以下修复方案:

增加 html-minifier 配置,用于忽略插值表达式片段。:ignoreCustomFragments = [/{{[\s\S]*?}}/] 。

Bug2

增加配置后,webpack 编译成功。但是打开小程序编辑器,体验 dist 目录结果:项目无法运行。排查发现编译结果出现问题。

<!-- 能正常运行(输入输出内容一致)-->

<!-- 输入 -->
<div class="{{a?'aa':'bb'}}">1</div>
<!-- 输出 -->
<div class="{{a?'aa':'bb'}}">1</div>
<!-- 不能正常运行(输入输出内容不一致)-->

<!-- 输入 -->
<div class='{{a?"aa":"bb"}}'>1</div>
<!-- 输出 -->
<div class="{{a?"aa":"bb"}}">1</div>

这个编译问题是在我们加了忽略插值表达式的配置后才出现的。刚才添加的配置,影响了标签属性引号的处理。

我们可以找到 html-minifier 的相关源码进行分析:

// 是否禁止属性转译
if (!options.preventAttributesEscaping) {
  // 是否有指定过标签属性的引号是什么
  if (typeof options.quoteCharacter === 'undefined') {
    var apos = (attrValue.match(/'/g) || []).length;
    var quot = (attrValue.match(/"/g) || []).length;
    attrQuote = apos < quot ? '\'' : '"';
  } else {
    attrQuote = options.quoteCharacter === '\'' ? '\'' : '"';
  }

  // 根据属性引号值
  // 按需转译属性值内实体字符
  if (attrQuote === '"') {
    attrValue = attrValue.replace(/"/g, '&#34;');
  } else {
    attrValue = attrValue.replace(/'/g, '&#39;');
  }
}

emittedAttrValue = attrQuote + attrValue + attrQuote;

由于我们没有特别配置过 quoteCharacter ,根据源码逻辑,他会走入 typeof options.quoteCharacter === 'undefined' 分支。

该分支逻辑是对 attrValue 中包含的单/双引号的个数进行比较:属性值中双引号多,属性引号应当用单引号,反之亦然。举个具体例子:

<div class='abcd"e'>1</div>

这个例子中的属性值 attrValue 是 abcd"e,放进前面这段分支逻辑处理,代码逻辑会认为,这个属性值中有一个双引号,零个单引号,因此当前的属性值一定是被单引号括住,即 attrQuote 是单引号。

为什么会有这样的判断逻辑?

我们可以进一步查看 html 的相关规范。对于单引号属性值语法、双引号属性值语法,有规定:

Single-quoted attribute value syntax
The attribute name, followed by zero or more ASCII whitespace, followed by a single U+003D EQUALS SIGN character, followed by zero or more ASCII whitespace, followed by a single U+0027 APOSTROPHE character ('), followed by the attribute value, which, in addition to the requirements given above for attribute values, must not contain any literal U+0027 APOSTROPHE characters ('), and finally followed by a second single U+0027 APOSTROPHE character (').

Double-quoted attribute value syntax
The attribute name, followed by zero or more ASCII whitespace, followed by a single U+003D EQUALS SIGN character, followed by zero or more ASCII whitespace, followed by a single U+0022 QUOTATION MARK character ("), followed by the attribute value, which, in addition to the requirements given above for attribute values, must not contain any literal U+0022 QUOTATION MARK characters ("), and finally followed by a second single U+0022 QUOTATION MARK character (").

基于单引号的语法规范,我们画个图来快速理解下:
image

  1. 属性名 name
  2. 后面可以有零或若干个空格
  3. 等号 (EQUALS SIGN character)
  4. 后面可以有零或若干个空格
  5. 一个单引号 (single U+0027 APOSTROPHE character ('))
  6. 属性值 value,值中不可以有单引号
  7. 一个单引号 (single U+0027 APOSTROPHE character ('))

我们可以快速测试一下以下3个用例(文章后面也会再提及)

// 用例1
a.innerHTML =
  '<div testsome  = "a"aa">123</div>'
// 用例2
a.innerHTML =
  '<div testsome  = "a\"aa">123</div>'
// 用例3
a.innerHTML =
  '<div testsome  = "a&quot;aa">123</div>'

前两者的 html 会解析成
image

第三种写字符实体的会解析成
image

基于对规范的理解,我们再回过头看刚刚的 html-minifier 的实现,可以意识到,这个库是对 html 规范进行了更宽松的处理(允许属性值中含有引号,并帮你按需转译),他对于属性值的单双引号的处理逻辑是:“对 attrValue 中包含的单/双引号的个数进行比较:属性值中双引号多,属性引号用单引号,反之亦然。”。

这么做实际是为了,在没有指定单双引号值配置的前提下,尝试检查属性值中是否含有双引号或单引号,以此来推测,当前属性值是用双引号还是单引号括着的。

假如值内,有且主要是单引号,那外部肯定是用双引号,反之亦然,确定好属性引号后,再将属性值中含有的相关引号转换成字符实体,以免造成用例1/2中的不在预期内的解析结果。

由于我们前面设置了 ignoreCustomFragments,将所有插值表达式忽略掉,那么根据逻辑,当前的属性引号就会被认为应该取双引号,导致这个bug:

<!-- 输入
  插值表达式被忽略 属性值为空字符串
  零单引号 零双引号 则属性引号为双引号 -->
<div class='{{a?"aa":"bb"}}'>1</div>
<!-- 输出
  属性引号为双引号 表达式内也正好是双引号
  小程序运行报错 -->
<div class="{{a?"aa":"bb"}}">1</div>
而为了解决这个连锁 bug2,我们可以考虑把 preventAttributesEscaping 设为 true,不让 html-minifier 进行属性值引号的处理。

基于以上对 html 规范的理解,假设我们这么做,会引入 bug3,就是用例1/2 所示的属性值中含有应当被转译的实体字符:

预期:
image

实际:
image

因此最正确的选择应该是改业务代码,特殊字符应该用字符实体来代替。

至此,可能有人早就在质疑,为什么不直接用实体字符,为什么要写这种奇葩代码:

<view>
  500元≤累积业绩{{'<'}}1000元
</view>

因为小程序不支持直接在 wxml 中书写实体字符,实体字符会被当作普通的字符串进行展示。而直接写 < ,小程序开发工具本身也会解析失败,因为会把他当作标签的开头。

因此才会有开发者,曲线的利用插值表达式,将' < '单拎出来,不让 wxml 的 parser 处理。但是其实可以使用小程序提供的 text 组件,该组件支持 decode 参数,decode 可以解析以下实体字符:

&nbsp; &lt; &gt; &amp; &apos; &ensp; &emsp;

五、总结

<!-- web 能正常显示 < 符号 -->
<div><</div>

<!-- web 能正常显示 < 符号 -->
<div>&lt;</div>

<!-- 小程序解析出错、html-minifier解析出错 -->
<div><</div>

<!-- 小程序直接显示 &lt; -->
<div>&lt;</div>

<!-- html-minifier解析出错 需要额外加若干配置来解决 -->
<div>{{'<'}}</div>

最后, wxml-loader 的编写其实很简单,难点总是在于兼容各种人写出来的代码。本文用较大的篇幅记录了一次 debug 的过程,在已有项目中使用我们所编写的 wxml-loader 时,可以通过项目实际情况,按需配置 ignoreCustomFragments 和 preventAttributesEscaping 参数规避文中所说的部分问题。

当然,如果团队代码书写规范,更正确的操作应该是迎合小程序规则,使用 text 来解决问题,就不会有这么多衍生的 bug。

同时,在踩坑过程中我们还发现一个“彩蛋”,就是 sax 作为 html parser,一直都没有掺合进来折磨我们,报错的一直都是小程序本身和 html-minifier 库。这也可以说明 html parser 的割裂问题,各自有自己的 htmlParser 的实现。

而现代化的工具一般都统一了解析方式,比如 EStree / PostCSS 等,就是为了统一定个标准出现的。html-minifier 虽然是个成熟的库,但是也比较老了,有兴趣的小伙伴可以了解一下 unifiedjs ,它定义了一个通用语法树结构, 旗下 markdown / html / text / Graphviz 互转很方便。

六、参考链接

https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
https://github.com/kangax/html-minifier/blob/583e0861ee852a76acb1e8ec00b3de35a024927d/src/htmlminifier.js#L592

------------------------- 我是彩蛋分割线

Hello,各位老伙计,不知道你们有没有发现,我们的公众号多了两个菜单-> 内推 和 店铺。

上一篇文章中我们提到,希望把天赋带到公众号,捣腾一番。思来想去,觉得大多数人都在开课,而我们作为全职选手,其实没有那么多的精力去做这样的事情。

但是我们却可以帮忙模拟面试!之所以有这样的想法,是因为可能有校招/社招小伙伴们不了解当下的面试趋势和难度,以及多少有点对实战面试有抵触心理和些许恐惧,或者是害怕没有准备好,浪费了面试机会。

那么我们就是想为这类小伙伴提供一个真人模拟面试的机会。那么我们为什么能有底气做这件事呢?首先我们是一群来自不同大厂的小伙伴,从能力上,多少还是有保证的(拍胸脯),其次,我们人多(?),如果一个人持续做模拟面试这件事,那么其实是很耗费时间精力的,毕竟一次面试时间也不短。但是我们有多位靠谱的小伙伴可以持续性提供这样的服务,所以相对而言能够保证把这件事持续做下去。

以及我们也会考虑提供简历修改意见等服务,因为有很多小伙伴苦于做了事情,却不知道怎么去写去表达,那么我们可以一一帮你解决这类似问题。

当然,这个事情还在筹划中,我们的店铺中的相关服务商品,也还没有完善好,但是你们已经可以访问店铺中的商品了。伙计们不妨在评论区或者私信告诉我们有什么建议或者想法,或者是其他希望我们提供的帮助,因为我们目前想要做的就是集思广益,看一下我们能为大家做些什么有意义的事。以上~

HZFE 快报002

技术快读

Safari中的 CSS Grid 检查器介绍

CSS Grid 布局可以灵活的实现网格结构,布局能力极强。但是网格定义本身不可见,开发者容易困惑为什么布局不能按预期进行。CSS Grid 布局检查器令开发者能看到网格的结构和它在页面上的效果,令使用 CSS Grid 布局的工作更加平易近人,更容易推理。现在你可以在 Safari Technology Preview 123 版本中体验 CSS Grid 布局检查器。

https://webkit.org/blog/11588/introducing-css-grid-inspector/

Edge Canary 版本提供性能模式用于改善内存、CPU和电池的使用

目前还不清楚性能模式到底是如何改变 Edge 的,但它确实影响了睡眠标签的功能。如果你启用性能模式,那么睡眠标签的超时时间将被锁定为5分钟。

微软今年早些时候在 Edge 中引入了睡眠标签,当你打开若干浏览器标签页时,浏览器可以自动释放非活动标签页占用的系统资源。这有助于正在使用的标签页更好地运行并阻止浏览器在后台占用内存和 CPU 资源。

Edge 的性能模式可能会对笔记本用户最有用,因为浏览器往往对电池寿命有很大影响。在过去六个月里,谷歌也一直在努力改善 Chrome 浏览器的性能和电池使用。

https://www.theverge.com/2021/4/19/22391505/microsoft-edge-performance-mode-ram-cpu-battery-usage

Firefox Nightly 和 Beta 版本已提供对 QUIC 和 HTTP/3 支持

在 Firefox Nightly 和 Firefox Beta 中已经默认启用对 QUIC 和 HTTP/3 的支持。火狐计划在 Firefox 88 稳定版中发布该特性。HTTP/3 将在5月底前默认可用。

https://hacks.mozilla.org/2021/04/quic-and-http-3-support-now-in-firefox-nightly-and-beta/

Tailwind UI 现已支持 React、Vue

从去年 Tailwind UI 发布后,官方示例提供了大量由 Tailwind 构建的专业设计示例,并且都是纯 HTML 的,这使 Tailwind UI 可以适应于任何模板语言或者框架。

现今,React 和 Vue3 的使用示例已经被官方完善,这将使开发者更容易在项目中使用 Tailwind。

https://blog.tailwindcss.com/tailwind-ui-now-with-react-and-vue-support

缓慢而稳定:将 Sentry 的整个前端部分重构为 TypeScript

最近,Sentry 将其前端 React 代码库从 JavaScript 完全转换为 TypeScript。这个长达一年的工作涵盖了工程团队的十几个成员,1100个文件和95000行的代码。

https://blog.sentry.io/2021/04/12/slow-and-steady-converting-sentrys-entire-frontend-to-typescript

真实场景下的 CSS 与 CSS-in-JS 性能对比

如果您关心网站的负载性能,请不要使用运行时 CSS-in-JS。运行时 CSS-in-JS 会对你的网页产生明显的影响(主要是对于低端设备和网络连接较慢或数据较贵的地区)。

文章主要从3种方式进行测试:

  1. Network(JS 和 CSS的资源大小、覆盖率、请求数)
  2. Lighthouse 审查(带有移动预设的性能审查)
  3. 性能分析(页面加载的测试,拖拽交互测试)

https://pustelto.com/blog/css-vs-css-in-js-perf/

使用 DuckDuckGo 扩展来阻止FLoC(谷歌在 Chrome 中的新跟踪方法)

谷歌创造了一种名为 FLoC 的新追踪方法,将其放在 Chrome 浏览器中,并自动为数百万用户启用该功能。

FLoC 对隐私不利。它根据你的兴趣和人口统计学,浏览历史进行分析,对你进行分组,以便在没有第三方 cookies 的情况下实现广告和其他内容定位。

你可以使用 DuckDuckGo Chrome 扩展程序来阻止 FLoC 的跟踪。

https://spreadprivacy.com/block-floc-with-duckduckgo/

金融科技

顺丰控股

顺丰控股发布一季报,一季度净亏损9.89亿元,同比盈转亏;营收426.2亿元,同比增长27.07%。数据显示,陆股通一季度增持顺丰控股超1%公司股份。

爱尔眼科

爱尔眼科2021年4月22日晚间发布2020年年报称,2020年归属于母公司所有者的净利润17.24亿元,同比增长25.01%;营业收入119.12亿元,同比增长19.24%;基本每股收益0.4231元,同比增长23.28%。

英科医疗

英科医疗发布一季报,一季度净利润37.36亿元,同比增长2791.66%;营收67.35亿元,同比增长770.86%。

美国航空

美国航空发布一季报,2021年第一季度每股亏损1.97美元,市场预期亏损2.88美元,去年同期亏损5.26美元;净亏损12.5亿美元,上年同期亏损22.41亿美元;总运营收入40.08亿美元,上年同期为85.15亿美元。

**工程院确定577位有效候选人 茅台总工王莉未在列

今年2月份,茅台工程师王莉进入**工程院院士候选名单引发热议,现在**工程院公布了577位有效候选人,王莉不在其中。

4月23日,**工程院在官网上发布了《**工程院2021年院士增选有效候选人名单》,表示经**工程院主席团审议,确定2021年院士增选有效候选人577位,根据《**工程院院士增选工作实施办法》,现予公布。

https://www.cnbeta.com/articles/tech/1118919.htm

比特币:7年来首次跌破50天均线

今日亚太早盘,比特币交投于51500美元/枚附近。加密货币的交易价格近半年来扶摇直上。但比特币价格在此前大涨冲破6万美元后转而“跳水”,本周二自2014年来首次跌破50日均线。不少分析师预计比特币还将面临进一步大跌风险,出现重大修正走势。

https://www.cnbeta.com/articles/tech/1118915.htm

旧闻回顾:OKEx CEO:我们将永远不会看到 BTC 再次低于5万美元

2月18日,OKEx CEO Jay Hao在推上表示,2021年1月:我们永远不会看到 BTC 再次低于3万美元。2021年2月:我们将永远不会看到BTC再次低于5万美元。这仅仅是个开始。

https://www.8btc.com/article/6598061

库克:苹果搭载 M1 芯片的 Mac 销量超过英特尔版本

苹果 CEO 库克称,搭载 M1 芯片的 Mac 销量已经超越了搭载英特尔芯片的型号,占据总销量的绝大部分。苹果预计会在4月28日的财报电话会议上披露更多有关信息。

http://finance.sina.com.cn/stock/relnews/us/2021-04-23/doc-ikmxzfmk8498770.shtml

美国特斯拉Model Y长续航版起售价上调500美元

据特斯拉美国官网,特斯拉Model Y长续航版起售价为5.099万美元,此前为5.049万美元,上调500美元。

特斯拉深夜再发声明:已提交纸质和电子版数据,毫无保留配合监管调查

特斯拉称,我们将毫无保留地配合监管部门开展深入调查,开诚布公接受社会监督。我们愿意在客户同意、政府指定或监督的情况下,三方共同见证,在全国范围内任意有资质的权威检测机构进行检测。

垂直居中的一百零八种方式中文章中 一个问题

常用水平垂直居中方法

绝对定位(父级position: relative)

method1(need't height and width)

/*  or inline-block  */
div {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}

这里还是需要宽高的吧?不然就全屏了,和常用水平垂直居中方法相悖了?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.