Webpack 2 in Action

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

传统工具中,流程是,将 js, css, html 各自合并,压缩,形式一个或多个文件,分别在各处引用。

但 webpack 相对于之前的工具区别于,所有的东西都是资源,像 css, js, image 亦或 json 等,可以通过 loader 来进行加载。
同时,它有模块机制,会根据依赖,去把代码自动放在一起,而不用开发的配置。
接下来,一起来走一个流程,来熟悉下配置。


安装使用 Webpack

1
2
3
4
# 更推荐使用 yarn 来进行依赖库的操作
$ yarn add --dev webpack webpack-dev-server
# 为了更方便使用 webpack,建议全局安装
$ yarn global add --dev webpack webpack-dev-server

在项目中创建 webpack.config.js 即可开启使用。

可以依据不同环境,增设不同的配置文件 webpack.production.config.js


一切都在配置文件

Webpack 所有的配置都在 webpack.config.js 文件中。其中包括以下几个大的类别:

Context/Entry/Output

这是几个必备基础配置,我们来一一讲解:

  • context: 配置 entryloader 工作所在的根目录。
  • entry: 应用的入口文件,该文件和其依赖,最终会被编译到一个文件。(可以配置为多个对象,编译出对应个数的结果文件。)
  • output: 入口文件编译后的配置项,可以是一个固定字符串,也可是以一个 [name].[hash].bundle.js 的变量配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
let config = {
context: path.resolve(__dirname, 'src'),
entry: {
app: './main.jsx'
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: "[name].[hash].bundle.js"
}
}

Module

Webpack 是设计为处理 JavaScript 文件的,但其也可以处理任何的文件类型,这归功于强大的 Loaders 机制。

Loader 的使用方法是,通过正则匹配到一些类型的文件,然后对其依次经过配置 loader 的处理。Loader 可以配置多个,倒序依次处理。

示例中,是对 scss 文件的处理,先由 sass-loader 进行编译,然后交由 css-loader,最后由 style-loader 来处理。

1
2
3
4
5
6
7
8
9
10
11
let config = {
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
]}
]}
}

Plugins

和 Module 针对文件类型不同的是 Plugin 处理的是:下面,主要讲几个常用的 Plugin 和配置:

- webpack.HotModuleReplacementPlugin

webpack 内置 Plugin,自动热加载,就是在开发时,一旦有文件改动,浏览器会自动刷新。

- webpack.optimize.CommonsChunkPlugin

正如其名,它会让引用模块中重复的地方取出,做成一个单独的文件,这样可以将一些公共的库取出,降低改动带来的更新成本。

如果你正在将应用拆解,打包成多个 output 的话(如果应用的某部分有大量不需要提前加载的 JS 的话,这样做会很有用),那么在这些文件里就有可能出现重复的代码,因为在解决依赖问题的时候它们是互相不干预的。幸好,Webpack 有一个内建插件 CommonsChunk 来处理这个问题:

现在,在 output 的文件里,如果有任意模块加载了两次或更多(通过 minChunks 设置该值),它就会被打包进一个叫 commons.js 的文件里,后面你就可以在客户端缓存这个文件了。当然,这肯定会造成一次额外的请求,但是却避免了客户端多次下载相同库的问题。所以在很多场景下,这都是提升速度的举措。

- webpack.optimize.UglifyJsPlugin

代码压缩,用于生产环境。

- webpack.ProvidePlugin

全局挂载插件,用于挂载老的代码,如 jQuery 之类的。

- Extract Text Plugin

把 CSS 从 JS 中的 import/reuqre 中取出来,放到一个单独的 CSS 文件中。

- HtmlWebpackPlugin

不用开发人员自己在 index.html 中加 bundle.js, bundle.css 等 output 文件,因为这可能是一个 hash 值,这个插件会帮你搞定。

效果:

1
2
3
<link href="/app.4683be2.css" rel="stylesheet"></head>
...
<script type="text/javascript" src="/app.2e17047c719b4525dc77.bundle.js"></script>

- CopyWebpackPlugin

拷贝资源插件
像用了 ant.design,这里也会产生一些文件。

Resolve

最常用的,就是 alias,给一个模块路径起上一个别名,这样在每次 import 时,可以少写很多代码。

Webpack DevServer

DevServer 是一个内建的 HTTP 服务器的独立程序,可通过 webpack-dev-server 命令启动,为开发时提供方便。

它也可以使用 webpack.config 文件来进行配置,或通过命令行参数来进行配置,但有点参数只能通过命令行参数。

一种是命令行配置:

1
$ webpack-dev-server --open --host 0.0.0.0 --port 5000

另一种是在 webpack.config.js 中加入配置项目

1
2
3
4
5
6
7
let config = {
devServer: {
contentBase: path.resolve(__dirname, 'src'),
historyApiFallback: true,
hot: true
}
}

Other Devtool/Externals

Devtool 主要是配置生成何种方式的 Source Mpas。


其它事项

ECMAScript 2015 new syntax

一个有着代码洁癖的人,是不会让整个项目中再出现 ES 2015 前风格的代码的,如何解决 webpack.config 呢?

其实有个很简单的办法,把 webpack.config.js 改名成 webpack.config.babel.js 就可以了。

Webpack 在执行时会先用 Babel 把配置文件转成 ES5 代码再继续处理。一切 Babel 支持的语言特性都可以用。


REF::


Git 201 - Multiple Users Config



公司用 git commit 来统计数据后,一台电脑上的 git 就有了多种配置。


方案一、单独配置

除了 global 外,每个 repo 都会有自己的配置项,可以进行单独配置。

1
$ git config user.name "Lanvige Jiang" && git config user.email lanvige@example.com

The values will then be stored in in the .git/config for that repo rather than your global configuration file.

原理是 add following information in your local .git/config file

1
2
3
[user]
name = Your Name
email = your.email@gmail.com

Check,确保

1
2
3
4
5
$ git config user.name
$ git config user.email
# 或者查看全部,包括 global 和 local
$ git config --list

但这个很繁琐,每个新项目都要设置一次,而且提交时没有报警,很容易忘记。


方案二、每次提交时带上配置

1
git -c user.name='Lanvige Jiang' -c user.email='lanvige@example.com' commit -m '...'

REF::

Koa2 Boilerplate

这是我整理的一个 koa2 + es7 的一个最佳实践,用了一些新的 Feature,完成了全部流程,从 request 到 service 和 DB(Sequlize)到 response。


Features

koa2 & koa-router

koa 相对于 express 更吸引开发者的地方莫过于 U 型 Middleware 机制。

Babel

目前 node v6 已经支持了绝大多数新的语法,http://node.green/

目前用下来只有两个 feature,就是 asyncFuncation 和 module,所以在配置项中,只需要开启这两项就够了。async 会被编译为 generater。

1
2
3
4
{
"presets": ["es2017"],
"sourceMaps": "both"
}

AsyncFuncation

通过 babel 来实现了 async-await (为了 async 的美可以做出任何牺牲)。

Module

ES 6 中模块化有一些显著的变化,像 import/export,具体见

标准已经制定:修改文件名后缀为 .mjs 但目前仍需要 babel 来转。

DI Container

因为没有模块,所以大量的引用散落在各处,一量修改,真的是痛不堪言。

DI 可以统一管理这些依赖,只需要修改一处,当然最大的好处莫过于解耦,便于测试。

这里用的是 Awilix

Environment

通过 yenv 来实现环境变量管理。

Sequlize

我们在项目中大量的使用了 Sequlize,也吐槽了很多,这里只是一个最简单的结合示例。


Directory structure

一般通过 node 创建的 web 项目,通用的作法是将源码等放在一个 src 的目录下,这样的好处是为了方便编译,感谢 babel,可以提前享受 ES 新语法。

后端项目也有一些这样的实践,但这里并没有采用,原因是随着 node 对标准的支持,在不久的将来,我们线上的代码是不再需要编译的。可以像 rails 一下直接运行(好期待那天)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.
├── app
│   ├── apis
│   ├── beapis
│   ├── models
│   ├── services
│   └── validators
├── bin
│   ├── _babel.js
│   └── server.js
├── config
│   ├── application.yml
│   ├── database.yml
│   └── redis.yml.example
├── db
├── lib
│   ├── createContainer.js
│   ├── createServer.js
│   └── middleware
├── .babelrc
├── Dockerfile
├── yarn.lock
└── package.json

当然目前还是需要编译的,这样就不需要在服务器上跑 babel-runtime。dist 是编译后的目录,通过 npm 对具体目录做了一些单独的编译。

  • app: 项目主要的业务逻辑代码。
    • api: 本层主要处理到达的请求,将参数做整理,然后交由 service 层。
    • services: 服务层从 repo 层取数据,然后拼接加工,最后返回 api 层。
    • model: 项目的 models。
  • bin: babel 需要一个启动文件。
  • config: 环境变量配置目录。
  • db: 数据库的一些资源。
  • dist: 编译后的文件。
  • lib: 一些系统类库,处理环境变量。和工具类。
    • middleware: middleware。
  • test: 测试用例。


npm run scripts

这里定义了一些常用的启动命令:

  • start: Used by the production environment to start the app. This will run a compiled version, so you need to execute build first.
  • build: Runs the babel CLI to compile the app. Files are emitted to dist/.
  • dev: Runs the app in development mode - uses babel-register to compile on-the-fly. Also uses nodemon to automatically restart when stuff changes.
  • debug: Runs the app in development mode with icebug (a combo of nodemon + node-inspector).
  • test: Runs mocha tests.
  • test-watch: Runs mocha tests in watch-mode.
  • lint: Lints the code in src and test with eslint.
  • lint-watch: Same as above, in watch-mode.

Tip: to pass additional arguments to the actual CLI’s being called, do it like in this example:

1
npm run test -- --debug

2017

正月15前的最后一个工作日,路上依然是假日状态的通畅,不过也是仅有的一天了。毕竟张江的道路已经堵了一周了。

谈谈正事吧,是时候跟旧的一年完全说再见,投入到新的一年中了。

做更好的自己

最近苦恼的事情,经常在一些地方发现白发,虽然少白已是事实,但掉的头发还几乎都是黑发。有种忽然老去的赶脚。这赶脚一来,影响了整个冬天。

有一种时光不再的感觉。忽然觉得过的很不够好,不够硬气,不够阳光。

看了下镜子,有种浪费身材的感觉。决定来年穿出精神来。

头发也是叭着,虽然白了一些,但更可怕的是没有精神。

做成一件小事情

这跟今年的年终奖有关,确实是伤心,毕竟努力了这一年,到头都没有个认可。可想想,这也许是技术人的共悲之处,有人说,三年技术,余下运营。在这个运营主导的公司,确实挺形象。

但,事实就是事实,今年的事实还会成为明年的现实。要这样吗。

所以,今天要做一件小事,当年,事情还不知道,只是有几个 side project 计划。

但凡坚持,总有回报。

MySQL - Users and Permissions

  1. 1. 1. MySQL 用户管理
    1. 1.1. 1.1 查看用户
      1. 1.1.1. > Host 中有两种情况 localhost, %
    2. 1.2. 1.2 创建用户
  2. 2. 2. 权限基本操作
    1. 2.1. 2.1 查看 root 的权限
    2. 2.2. 2.2 自定义用户的权限
      1. 2.2.1. 给 dbman 用户配置权限。
    3. 2.3. 2.3 验证
    4. 2.4. 2.4 删除用户
    5. 2.5. 2.5 Disable remote root logins into MySQL
  3. 3. 3. 权限的级别定义
  4. 4. REF::

MySQL 用户、权限基本操作


1. MySQL 用户管理

MySQL 的用户管理是在一张系统数据库 mysql > user 里进行管理的。

用户的操作,都是对该库该表进行操作。

1.1 查看用户

1
SELECT User, Host FROM mysql.user;
1
2
3
4
5
6
7
+--------+-----------+
| User | Host |
+--------+-----------+
| dbman | % |
| root | % |
| root | localhost |
+--------+-----------+

> Host 中有两种情况 localhost, %

  • localhost 表示只能本地登录
  • % 表示支持远程登录

1.2 创建用户

1
CREATE USER 'dbman'@'%' IDENTIFIED BY 'password';


2. 权限基本操作

因为一个用户在远程和本地登录时可以有不同的权限,所以这里查看权限时,要加上 Host 条件的。

2.1 查看 root 的权限

1
SHOW GRANTS FOR 'root'@'%';

显示 root 在远程访问中有着所有的权限。

1
2
3
4
5
+-------------------------------------------------------------+
| Grants for root@% |
+-------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION |
+-------------------------------------------------------------+

2.2 自定义用户的权限

给 dbman 用户配置权限。

1
2
3
4
5
6
7
8
9
10
11
-- 远程连接,所有数据库,所有权限
GRANT ALL PRIVILEGES ON *.* TO 'dbman'@'%';
-- 本地连接,指定数据库 (db_test),所有权限,并设连接密码
GRANT ALL PRIVILEGES ON db_test.* To 'dbman'@'localhost' IDENTIFIED BY 'password';
-- 远程连接,指定数据库,指定权限,并设连接密码
GRANT SELECT,UPDATE ON db_test.* To 'dbman'@'%' IDENTIFIED BY 'password';
-- After making changes to permissions/user accounts, make sure you flush the provilege tables using the following command:
FLUSH PRIVILEGES;

2.3 验证

1
SHOW GRANTS FOR 'dbman'@'%';
1
2
3
4
5
+------------------------------------+
| Grants for d2team@% |
+------------------------------------+
| GRANT USAGE ON *.* TO 'd2team'@'%' |
+------------------------------------+

2.4 删除用户

Just as you can delete databases with DROP, you can use DROP to delete a user altogether:

1
DROP USER ‘demo’@‘localhost’;

2.5 Disable remote root logins into MySQL

新的 DB 里都会给两个 root 的,一个是 % 另一个是 localhost,而 remote 是最危险的,别人可以通过该用户来进行攻击。

1
2
3
4
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
-- After making changes to permissions/user accounts, make sure you flush the provilege tables using the following command:
FLUSH PRIVILEGES;


3. 权限的级别定义

Here is a short list of other common possible permissions that users can enjoy.

  • ALL PRIVILEGES - as we saw previously, this would allow a MySQL user all access to a designated database (or if no database is selected, across the system)
  • CREATE - allows them to create new tables or databases
  • DROP - allows them to them to delete tables or databases
  • DELETE - allows them to delete rows from tables
  • INSERT - allows them to insert rows into tables
  • SELECT - allows them to use the Select command to read through databases
  • UPDATE - allow them to update table rows
  • GRANT OPTION - allows them to grant or remove other users’ privileges. To provide a specific user with a permission, you can use this framework:
1
GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'localhost’;


REF::

NAS

我觉得 双12 最大的做用是让人认清 双11 到底哪些东西没买后悔,哪些买了后悔。

于是在 0点0分,拿到了念念许久的 Synology 716+II

起因是网盘各家纷倒,最后百度也在限流,而且上传的东西不属于自己,也让人反感。

最后,这个小结写于一个月后,早已没有对设备的新鲜感,但更好的是可以有一些使用感受。

说到 NAS 有很多种方案

  • 在路由器上外挂个硬盘,现在就是这样做的,只是路由器把硬盘弄坏了。
  • 买个带功能的硬盘,像西数的 3T,价格便宜不少。
  • Synology,说实话买之前我不知道群晖有多好,而且价格超级贵。不过我只记得同事说的一句,群晖是卖软件的。

感受

群晖真的是卖软件的。

场景

个人有收藏照片,经典电影的习惯,虽然电影不怎么更新了,但照片的数量和大小是剧增。要感谢手机相机的提升。

之前,硬盘里的照片只是用来存的,而不是用来看的。没有功能,也就没有需求。

群晖中的一个功能,DS Photos,一下子打开了这种需求。因为无论是在手机上,电脑上,看照片太方便了。

然后就是由此产生的一堆的问题,比如照片归类,排序。之前一堆照片是没有用的,所以乱放也不知道,现在随便一点一看,全是问题。其实

Deploy Node Application in Docker with Capistrano

之前有尝试过 shipit,不过其方式,插件和 bug,都蛮让人失望的。


Prepare

1
$ bundle init

修改 Gemfile 内容为以下:

1
2
3
source "http://ruby.taobao.org"
gem 'capistrano'

初始化当前目录为 Cap:

1
$ bundle exec cap install

会生成下面的一个目录结构(为简单,修改为prod.rb):

1
2
3
4
5
6
7
8
9
10
.
├── Capfile
├── config
│ ├── deploy
│ │ ├── prod.rb
│ │ └── staging.rb
│ └── deploy.rb
└── lib
└── capistrano
└── tasks


Cap Config

deploy.rb 文件主要是配置所有发布环境的公共配置

config/deploy.rb
1
2
3
set :application, 'd2labs_beta'
set :deploy_user, 'deploy'
set :repo_url, 'git@github.org:lanvige/test.git'

除了公共配置文件外,每个环境都有自己的配置文件:

config/depoly/prod.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
set :stage, :production
set :branch, 'master'
# Extended Server Syntax
server '10.10.10.1', user: 'deploy', roles: %w{web app db}
# used in case we're deploying multiple versions of the same
# app side by side. Also provides quick sanity checks when looking
# at filepaths
set :full_app_name, "#{fetch(:application)}"
## where to put the app
set :deploy_to, "/home/#{fetch(:deploy_user)}/apps/#{fetch(:full_app_name)}"

在Deploy 前,我们还需要添加一些功能,将site-enabled/nginx.conf的配置文件添加到Remote Server下。


Prepare


Deploy

The Screen Resolution

我是一个显示控,多年前为了买 DELL 2412,花费巨资,当时的 1080P 感觉这是要用十年,结果两三年后,2K 出现了,能把屏幕一分为二,左右分屏而用。心痒,入了 DELL 2515h,再后来 4K 电视出来,升,5K iMac 出来,,,额,太想要了。

那这些 720p, 1080p, 2K, 4K, 5K 到底是什么意思呢?有些简称的确让人理解起来很方便,但随着分辨率和组合的增多,这些字母组合着实令人困扰,有时我自己也不清不楚,于是总结了一下。


p & k

之前的叫法一直都是 p 结尾的,字母 p 意为逐行扫描 (progressive scan)。数字 1080 则表示垂直方向有 1080 条水平扫描线。也就是高 1080 个像素。

后来分辨率越来越大,在宽上超越了 1xxx 这个数值区间,达到了一个更大的数值。对显示分辨率的叫法也由 p 变为了以宽为主的 k。

这正是造成当前人们对分辨率概念混乱的原因,毕竟几十年我们在讨论电视分辨率时说的都是垂直分辨率,现在突然变成了意指水平分辨率的 4K电视,让人困惑。

而且 p 和 k 的叫法,所指的也只是主流的叫法
,不是每一家都这样叫的。如果你打开 youtube,你会看到它依然在用 p 作为主流显示,只是在边上备主 k。如:

p k
4320p 8K
2160p 4K
1440p HD


常见分辨率

水平用 k,垂直用 p

xK

叫法 x y alias devices
1K? 1280 720 HD (High Definition), 720p -
1280 1024 1.3K -
1680 1050 1050p P2213
2K 1920 1080 FHD (Full HD), 1080p, 准2K U241H
2048 1080 - -
2048 1152 QHD (Quad HD)真2K -
2560 1440 1440p, 超2K iMac 2012, U2515h, U2717d
4K 3840 2160 UHD (Ultra HD), 2160p, 准4K P2715Q, P2815Q
4096 2160 2160p, 真4K LG 31MU97
5K 5120 2800 2800p iMac 5K, UP2715K
8K 7680 4320 4320p -

过去的时代,是不用 k 来表示的,所以没有 1k 的概念。到了后来,才开始用水平表示法。才有了 k 的概念。

xP

name x y alias devices
720p 1280 720 720p -
1080p 1920 1080 - -

xxxxp 说的是分辨率的宽度。比如 1920x1080,就是 1080P3860x2160 就是 2160p


720p, 1080p

1080p(或全高清)

历史上,电视过去曾使用垂直分辨率来描述分辨率。因此1080p代表的是垂直分辨率。而几乎所有的高清电视的纵横比都是 1.78 : 1 (即16×9,又名“宽屏”),这意味着其水平分辨率为 1920 像素(即1920×1080)。

720p

720p 的像素数量大约为 1080p 的一半。目前,只有最小的电视和最便宜的电视采用720p分辨率,是向高清过渡的时代。


2k, 4k, 5k, 8k 分辨率

2K、4K 屏说的是分辨率的宽度。

2K 分辨率指的是屏幕分辨率达到了一种级别,指屏幕横向像素达到 2048 以上,垂直分辨率未指定。是国内数字影院的主流放映分辨率。

2K 分辨率有多种类别,最常见的显示器分辨率 2K 是指 2560×1440 (WQHD | Quad HD)

至于 2560x1440,有个说法: 因为 2560 既不靠 3K,也不靠 2K,所以正确叫法就是叫1440P。把这个分辨率叫成 2K 就是错误的。当然,所有人还是叫 2K。

4K 的主流分辨率是 4096x2160,也称 2160p 或超高清,但绝大多数人都更喜欢 4K 这一名称。

8K 的道理跟 4K 一样。如果你谈论的是电视,那么其水平像素和垂直像素均为 4K 电视的两倍:7680×4320。但这还没有成为一种电影分辨率,至少在现实中还未应用。我们距离8K电视成为主流还很遥远

MacBook, Router & WiFi Channel

周未因一个找不到 WiFi 信号的小问题,顺带研究了一把 WiFi Channel, Country, Router & MacBook 的关系,又长见识了。


找不到 5G

MacBook 会因连接 WiFi 2.4G 导致蓝牙键盘不灵,刚好本周未把本子带回家碰到同样的问题,上路由器上一看,不得了,清一色连接的都是 2.4G,而不是性能更好的 5G。

路由器把 2.4 和 5G 合并了,自动选择性能更好的模式。

于是就把路由器的模式关掉,也同时关掉了 2.4G 网络,只留下了 5G。然后很奇怪的问题就产生了,MacBook 间歇性的找不到 WiFi 信号。而且是找不到的时间居多,直致最后完全找不到,打开 2.4G 开关,使用正常。但同时,iPhone 6 Plus 等其它设备都可以正常使用。

这不符合极客精神,于是探究了下,打开路由器的设置,看到 5G 使用的信道是推荐的 36。试着换了一个信道,到 161,竟然好了。


信道与国家

在网上找到这么一张图,算是印证了自己的想法:

信道 36,40, 44, 48 在中国是禁用的。


MacBook、Channel & Country

继续探索,找到 MacBook 的 WiFi 设置:

可以看到,电脑的 WiFi 接收器也有一个参数配置:

  • Country Code
  • Supported Channels

这里跟上图的说明是一致的,也证明了换成 161 成功的原因。

同时也可以看到下方 WiFi 信号的参数:

  • Country Code
  • Channels

如果把路由器的信道改成 36,就会从这个页面里消失。

也就是说,我的这个路由器违反了国家规定,可以开启 36-48 这几个信道,但 MacBook 非常遵守法规,于是就无法找到 36信道的 WiFi 信号


疑问:为什么 iPhone 6s 又能使用信道 36?

难以说明的是为什么,iPhone 是可以使用 36 信道的 5G WiFi?难道法规改了?

没有找到确定的法律,但确实是, 36-44,这几个信道在中国被启用了。

最新的标准,可以见这里: List of WLAN channels

看来,这个 2011 款的 MacBook Pro 真的是有点老了,同时出问题的 iMac 27 也是 2011 款的。😓


疑问: +1, -1

为什么有的 +1,有的 -1,有的没有 Country Code,不是很理解?

REF::