Pick's Blog

穿梭在银河的火箭队员


  • Home

  • Archives

package.json 冷知识

Posted on 2019-05-23

版本号

  1. 指定版本:比如 1.2.2,遵循 大版本.次要版本.小版本 的格式规定,安装时只安装指定版本
  2. 波浪号(tilde)+指定版本:比如 ~1.2.2,表示安装 1.2.x 的最新版本(不低于 1.2.2 ),但是不安装1.3.x,也就是说安装时不改变大版本号和次要版本号
  3. 插入号(caret)+指定版本:比如 ˆ1.2.2 ,表示安装 1.x.x 的最新版本(不低于 1.2.2 ),但是不安装 2.x.x ,也就是说安装时不改变大版本号。需要注意的是,如果大版本号为 0 ,则插入号的行为与波浪号相同,这是因为此时处于开发阶段,即使是次要版本号变动,也可能带来程序的不兼容
  4. latest:安装最新版本

安装指令

  • npm i -S 即 npm install --save 即写入 dependencies,项目运行所依赖的模块
  • npm i -D 即 npm install --save-dev 即写入 devDependencies,项目开发所依赖的模块

关于 package-lock.json 的更新

如果 npm i xxx -D 后只提交了 package.json,就会导致其他人拉取到的 package.json 和 lock 文件不同,那么执行 npm i 时会根据 package.json 中的版本号以及语义含义去下载最新的包,并更新 lock

pkg.module 字段含义

  • pkg.module 字段要指向的应该是一个基于 ES6 模块规范的使用 ES5 语法书写的模块
  • 基于 ES6 模块规范是为了用户在使用我们的包时可以享受 Tree Shaking 带来的好处;使用 ES5 语法书写是为了用户在配置 babel 插件时可以放心的屏蔽node_modules 目录

相当于在一个包内同时发布了两种模块规范的版本。当打包工具遇到我们的模块时:

  1. 如果它已经支持pkg.module字段则会优先使用 ES6 模块规范的版本,这样可以启用 Tree Shaking 机制。
  2. 如果它还不识别pkg.module字段则会使用我们已经编译成 CommonJS 规范的版本,也不会阻碍打包流程。

关于模块化规范

Posted on 2019-04-25
  • AMD (Asynchronous Module Definition):发展自CommonJS规范,RequireJS是 AMD 规范的典型实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    define(['jquery', 'underscore'], function ($, _) {
    function a () {}; // 私有方法,没有被返回
    function b () {};
    function c () {};

    // 暴露公共方法
    return {
    b: b,
    c: c
    };
    });
  • CMD (Common Module Definition):发展自CommonJS规范,Sea.js是 CMD 规范的典型实现,唯一不被webpack所支持的模块化规范,其余都支持

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    define(function (require, exports, module) {
    var a = require('./a');
    var b = require('./b'); // 依赖可以就近书写

    // 通过 exports 对外提供接口
    exports.doSomething = function () {};

    // 或者通过 module.exports 提供整个接口
    module.exports = {};
    });
  • CommonJS:其前身是ServerJS,是Node.js中的模块化规范

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var $ = require('jquery');
    var _ = require('underscore');

    function a () {}; // 私有
    function b () {};
    function c () {};

    module.exports = {
    b: b,
    c: c
    };
  • UMD (Universal Module Definition): 同时兼容了 AMD 和CommonJS,而且还支持老式的全局变量规范

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    (function (root, factory) {
    if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
    } else if (typeof exports === 'object') {
    // Node, CommonJS之类的
    module.exports = factory(require('jquery'));
    } else {
    // 浏览器全局变量(root 即 window)
    root.returnExports = factory(root.jQuery);
    }
    }(this, function ($) {
    // 方法
    function myFunc () {};

    // 暴露公共方法
    return myFunc;
    }));
  • ES Module: ECMAScript 6的模块化标准语法

    1
    2
    3
    4
    5
    import {bar} from './b';
    console.log('a.mjs');
    console.log(bar());
    const foo = () => 'foo';
    export {foo};

Git workflow

Posted on 2019-04-05 | Edited on 2019-04-06

工作流的设计是日常开发工作中必须考虑的问题,关乎团队的协作模式,所谓「流」就是保证项目平稳、顺畅地向前迭代,本文介绍三种主要的 Git workflow

Git flow

出现最早,应用最广的一种工作流程,基于”版本发布”的工作流

  • 项目存在两个长期分支:主分支 master 、开发分支 develop;三种短期分支:功能分支 feature、补丁分支 hotfix、预发分支 release
  • master 用于存放对外发布的版本,任何时候在这个分支拿到的,都是稳定的分布版
  • develop 用于日常开发,存放最新的开发版
  • release 分支源于 develop 分支,用于发布之前(即合并到 master 之前)的预发布测试,结束以后必须合入 develop 和 master 分支
  • 一旦完成开发,三个短期分支就会被合并进 develop 或 master,然后被删除
  • 优点:清晰可控
  • 缺点:相对复杂,需要同时维护两个长期分支。对于有”持续发布”需求的项目,代码一有变动就需要部署一次,develop 需要频繁地合入 master,导致这两者的差别不大,没必要维护两个长期分支

Github flow

Github flow 是 Git flow 的简化版,专门配合”持续发布”。它是 Github.com 使用的工作流程

  • 它只有一个长期分支,就是 master,使用流程如下:
  • 第一步:根据需求,从 master 拉出新分支,不区分功能分支或补丁分支
  • 第二步:新分支开发完成后,或者需要讨论的时候,就向 master 发起一个 pull request(简称PR)
  • 第三步:Pull Request 既是一个通知,让别人注意到你的请求,又是一种对话机制,大家一起评审和讨论你的代码。对话过程中,你还可以不断提交代码
  • 第四步:你的 Pull Request 被接受,合并进 master,重新部署后,原来你拉出来的那个分支就被删除。(先部署再合并也可)
  • 优点:简单,对于”持续发布”的产品是最合适的流程
  • 缺点:假设了合入到 master 就能立刻发布,没有考虑发布窗口,往往需要另外新建一个 production 分支跟踪线上版本

Gitlab flow

Gitlab flow 是 Git flow 与 Github flow 的综合。它吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利

  • 最大原则叫做”上游优先”(upsteam first),即只存在一个主分支 master,它是所有其他分支的”上游”。只有上游分支采纳的代码变化,才能应用到其他分支
  • 对于”持续发布”的项目,它建议在 master 分支以外,再建立不同的环境分支。比如,”开发环境”的分支是 master,”预发环境”的分支是 pre-production,”生产环境”的分支是 production
  • 开发分支是预发分支的”上游”,预发分支又是生产分支的”上游”。代码的变化,必须由”上游”向”下游”发展
  • 对于”版本发布”的项目,建议的做法是每一个稳定版本,都要从 master 分支拉出一个分支,比如 2-3-stable、2-4-stable 等等

关于 rebase 和 merge

rebase 的含义是改变当前分支 branch out 的位置,merge 负责功能分支合并到主分支

  • git rebase 其实可以把它理解成是「重新设置基线」,将当前分支重新设置开始点,这样才能知道当前分支和需要比较的分支之间的差异
  • rebase 并没有进行合并操作,只是提取了当前分支的修改,将其复制在了目标分支的最新提交后面
  • 只对尚未推送的本地修改执行 rebase 操作清理历史,从不对已推送至别处的提交执行 rebase 操作,即不要在公共分支使用 rebase

常见的像素单位

Posted on 2019-04-02 | Edited on 2019-04-04

px

即像素,1px 代表屏幕上一个物理的像素点

  • 由于像素密度不同,同样 100px 的图片,在不同手机上显示的实际大小可能不同

DPI

像素密度的单位 dpi 是 Dots Per Inch 的缩写,即每英寸像素数量

  • Android 系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi)
  • 它们对应的 dp 到px 的系数分别为 0.75、1、1.5 和 2,这个系数乘以 dp 长度就是像素数 px

dp(dip)

Density independent pixels,设备无关像素

  • dp 与 dip 完全相同,只是名字不同而已。在早期的 Android 版本里多使用 dip,后来为了与 sp 统一就建议使用 dp 这个名字了
  • dp 与 px 换算公式如下: dp = (DPI/160) px

为什么使用 160dpi 作为标准

  • 因为第一款 Android 设备(HTC的T-Mobile G1)是属于 160dpi 的
  • 方便换算,其余三个分别是 160dpi 的 0.75、1.5、2 倍,若使用 240dpi 则会出现无限小数

关于字符编码

Posted on 2019-03-26 | Edited on 2019-03-28

Unicode

Universal Multiple-Octet Coded Character Set

  • 可以容纳世界上所有文字和符号的字符编码方案
  • 简称 UCS,俗称 Unicode,规定必须用两个字节,也就是16位来统一表示所有的字符
  • 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),0 - 255被用来表示大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122
  • 需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储

UTF-8

UCS Transfer Format

  • 互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示)
  • Unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节。从Unicode到UTF-8并不是直接的对应,而是要过一些算法和规则来转换
  • 总而言之:Unicode定义世界每个字符的索引值。UTF-8/UTF-16 实现 Unicode 的标准,把字符存储到存储介质中。

UTF-16

  • 编码以 16 位无符号整数为单位,我们把 Unicode 编码记作U。编码规则如下:
  • 如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)
  • 如果U≥0x10000,我们先计算U’=U-0x10000,然后将U’写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx
  • 为了将一个WORD的UTF-16编码与两个WORD的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate)

JavaScript 相关

  • ES6 新增的 codePointAt()、String.fromCodePoint()、for...of 能够正确识别32位的UTF-16编码
  • 所对应的旧接口依次是 charAt()、String.fromCharCode()、普通 for 循环,它们则没有这样的能力,只能识别16位的UTF-16编码

Pick

雷声自空旷遥远而来
5 posts
4 tags
© 2019 Pick
Powered by Hexo v3.8.0
|
Theme – NexT.Muse v7.0.1