分类
js

使用 webpack-mock-server 给组件库添加测试服务

再过一周,我就在我厂待满三年了。其实我的职业生涯还算比较顺利,除了第一次跳槽不太好,后面每个公司都选的不错,虽然远不能满足财务自由的梦想,但是几乎都能让我在技术上有所精进,在职业上也取得一定成长。

三年期间,我们做了不少产品,为了方便在不同产品之间复用代码,我把一些公共部分抽出来做成组件,独立开发和维护,并且通过 npm + GitHub Registry 管理依赖(这个部分,前面曾写过一篇文章《使用 GitHub Registry 托管私有 NPM 源》介绍)。

有一些组件,比如登录,独立出来开发没问题,但是测试比较难搞,为了它单独开发服务器有点太兴师动众。所幸我很快就找到 webpack-mock-server,它可以很方便的定义 API 接口,只要把它加到项目中,就能很容易的完成测试了。

使用方法

1. 安装

使用 npm 安装,并且添加配置文件。安装 typescript 是因为它默认会在项目根目录里找 webpack.mock.ts,我暂时不知道怎么不用 ts 写配置。

npm install -D webpack-mock-server typescript
const webpackMockServer = require("webpack-mock-server");
 
module.exports = {
  devServer: {
    before: webpackMockServer.use
  }
}

2. 配置接口

目前这个工具只会在根目录里找 webpack.mock.ts(或者说我用的还不太熟,只会这么做),好在写 express 配置并不复杂,也不需要 ts 语法:

import webpackMockServer from "webpack-mock-server";
 
// app is expressjs application
export default webpackMockServer.add((app, helper) => {
  // you can find more about expressjs here: https://expressjs.com/
  app.get("/testGet", (_req, res) => {
    res.json("JS get-object can be here. Random int:" + helper.getRandomInt());
  });
  app.post("/testPost", (_req, res) => {
    res.json("JS post-object can be here");
  });
});

3. 检查接口

接下来,正常启动 dev-server 即可:webpack-dev-server --config=build/webpack.dev.js,然后留心控制台,会多输出一个服务网址,比如:

WebpackMockServer. Started at http://localhost:8079/

这个服务一般是 dev-server 端口 -1,比如我的 dev-server 跑在 8080,那么它就在 8079。打开之后是如下所示的接口列表:

从中可以看到所有提供服务的接口,支持什么方法,点击还能查看返回结果,非常方便。

总结

使用这个工具,可以大大提升组件库的开发效率。目前我用的也不是很熟,文档中介绍的方法还没用完,也不清楚怎么不用 ts。先推荐给大家吧。

分类
vue

webpack 入口是 vue 文件时,无法合并 CSS

在多页网站中合并 CSS 是很常见的优化手法。一般来说,CSS 体积不会太大,使用同一份 CSS,改进用户点击链接后的加载速度,大部分收益都大于多加载几 K CSS 带来的损耗。

对于 UI 库来说也是如此,用统一的样式库,减少 import 时的心智负担,也是性价比很高的做法。

最开始我在 UI 库的入口文件里 export 所有组件,然后在其它仓库里用 import {component} from 'my-components' 使用组件。后来通过分析得知,这样做无法 tree-shaking,而且会导致组件库的重复引用,即 A import B,B import C,那么无论 A 里有没有用到 C(比如用到 B 的一个小功能 b1,它不依赖 C),都会把 C 的代码打包进去。

通过研读 Webpack 的 tree-shaking 文档,我得知也没有什么好办法可以规避这个问题,毕竟 JS 很灵活,你也不知道哪个开发者会搞个 eval('const myRequire = require'),如果要识别解析分辨所有情况太复杂,所以选择最保守的策略:认不出来具体功能的代码都给你带上。(早年我写 NerveNet 的时候,就是想不通这里怎么搞,最后坑掉了。早知道大家都选择绕开,说不定我的 NerveNet 也能如愿写出来了……)

总之,目前 lodash 的做法比较常见且能解决问题,即增加多入口,为每个可能用到的函数都打包独立的函数。这样需要引用那个就引用哪个,不用担心把整个 lodash 都打包进去。

于是我就立项开始重构我厂的几个前端库。然后很快就卡在 UI 库上面:无法生成合并过的 CSS 文件。Google 许久没有结果,吃饭前我灵机一动:vue-loader 必须搭配 VueLoaderPlugin 才能正确打包,会不会这个过程有 bug,导致如果我的入口都是 Vue 单文件组件,就会没法正确合并 CSS 文件。

然后我就测试了一下,代码大约如下:

// a.js
import './a.styl'

// b.js
import './b.styl'

可以生成合并过的 CSS 文件。与之相较,这样的 Vue 单文件组件就不行:

// a.vue
<style lang="stylus">
body
  font-size 16px
</style>

// b.vue
<style lang="stylus">
body
  color red
</style>

但是,同样是 vue 单文件组件,样式使用 import 的方式导入,就没问题:

// a.vue
<script>
import './a.styl';
</script>

// b.vue
<script>
import './b.styl';
</script>

现在可以确定是 vue-loader 或者 VueLoaderPlugin 有问题。不过最近身体欠佳,每天要花很多时间锻炼,另外还欠下不少坑要填,所以暂时没空去翻 issue 或者提 issue。哪位同学看见了,愿意帮忙的,可以搞一下,也算参与 开源社区建设了,功德无量。

分类
前端工具链

Webpack 4 笔记

之前的《Webpack 笔记》内容有些陈旧,不打算再改,改名为《Webpack 3 笔记》。今后关于 Webpack 4 的笔记写在这里。如果将来 Webpack API 再次发生巨大变化,类似 3->4 这样,就再开一篇。

分类
前端工具链

使用 Webpack 动态打包文件夹

各式各样功能强大的小语言是我厂机器编程的特色,为了让更多的同学提前感受到 DSL 的威力,我们开发了 demo 应用:https://demo.openresty.com.cn/

Demo 里面,需要添加一些范例代码,方便用户直接体验。这些代码,可以通过后端 API 获取,也可以直接编译到前端代码里。目前范例很少,直接打包到一起应该是最简单的做法。

但是如何打包是个问题。经过一些研究,我觉得这样做好:

  1. 负责小语言的同事直接把范例写在项目仓库里,Edgelang 就用 .edge 扩展名,Navlang 就用 .nav 扩展名
  2. 前端在 webpack 里实现一个 requireAll 的功能,把所有代码当成纯文本用 raw-loader 加载进来
  3. 这样添加了代码后,重新 build 一下就好。范例文件可以用 lazy-load 的方式加载

Webpack 提供了一个方法叫 require.context,可以深度遍历一个目录,返回一个 context module,用这个 API 我们就可以动态的加载这个目录下的文件——具体的讲解和参数说明大家看下文档吧,这个部分中文资料不太多,我不太确定译名。我们可以在范例代码的目录下放一个 index.js,负责加载所有代码范例:

function requireAll(r) {
  r.keys().forEach(r);
}

const Languages = [
  'edgelang',
  'navlang',
];

let context = require.context('./edgelang', true, /\.(edge|css)$/);
requireAll(context);
context = require.context('./navlang', true, /\.(nav|css)$/);
requireAll(context);

export default Languages;

然后我们改一下 webpack.config.js 就可以了。

module.exports = {
  module: {
    rules: [
      {
        test: /\.(nav|edge|fan)$/,
        use: 'raw-loader',
      },
    ],
  },
};
分类
开发工具

使用 Webpack + Mocha 进行单元测试(二)

作为一名远程工作者,我并不能保证100%的电源供应,就目前的经验来看,我大约有30%的时间靠电池工作。所以我对能耗也比较敏感,把 eslint 和单元测试(mocha)放在 webpack 里做热加载,我觉得实在没什么必要,还是单独写单独跑吧。

查看 mocha-webpack 的 README,它对自己的介绍是:mocha-webpack 基本上等效于 $ webpack test.js output.js && mocha output.js 命令的封装,但是更高效、更强大。

让我们忽略后半句,先不去研究它高效和强大在什么地方,只看前半句。如果本质如此的话,那就不复杂,我只要写一个 webpack 配置文件生成所有的测试,然后跑这些测试就行了。最终方案:

  1. 一个入口文件,import 所有测试文件
  2. 用 webpack 打包入口文件,忽略掉不需要测试的内容(比如 CSS)
  3. 跑这个测试
  4. 平时写测试随便改下 import 路径就行了

测试文件多而杂,一个一个 import 太麻烦,可以写一个脚本帮我们:

const context = require.context('.', true, /.+\.test\.js?$/);
context.keys().forEach(context);
module.exports = context;

然后配合这样的配置文件即可:

const path = require('path');
const nodeExternals = require('webpack-node-externals');
const {resolve} = require('./webpack.base.config');

resolve.alias.test = path.resolve(__dirname, '../test');

const config = {
  target: 'node',
  entry: 'test/index.js',
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'test.build.js',
  },
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
            },
          },
        ],
      },
      {
        test: /\.ya?ml$/,
        use: [
          'json-loader',
          'yaml-loader',
        ],
        exclude: /node_modules/
      },
      {
        test: /\.(css|styl)$/,
        loader: 'null-loader',
      },
      {
        test: /\.(png|jpg|gif|svg|woff2|eot|woff|ttf|ico)$/,
        loader: 'null-loader',
      },
      {
        test: /\.pug$/,
        loader: 'pug-plain-loader',
      },
    ],
  },
  mode: 'none',
  resolve,
};

module.exports = config;

执行的时候,直接用 shell 脚本来跑就行。

分类
测试

使用 Webpack + Mocha 进行单元测试(一)

我厂产品经过两年的打磨,目前功能基本稳定了,接下来的工作重点是用测试保证质量。除了继续丰富 E2E 测试,我还计划添加一些单元测试,用来确保一些重要函数和类正常工作。

所以就要选择框架。开始想试试近期比较热门的 Jest,找了些文章看了看,发现也没啥吸引我的特色,E2E 和 UI 我厂的 Navlang 目前独步江湖,无出其右者,考虑到以前用 Mocha 写过一些单元测试,所以决定继续用 Mocha。

但是已经很长时间没写了,所以想先研究下工具链。如果只是单文件的话,直接 mocha test.js 就好;如果测试文件用了 ESM,那么加上 @babel/register 也就够了,mocha —require @babel/register test.js

但是我们项目用到了 Vue,还用 Webpack 里的 resolve 定义了很多目录,所以为了能够兼容项目代码,我必须要 Mocha 结合 Webpack,用这个关键词一搜索,得到两个结论:mocha-webpack 和 mocha-loader。

前者已经一年多没更新了,而且要求 mocha@5,所以我就不想用了。转过头研究 mocha-loader,经过反复试验,加上阅读源码,我得出结论:

mocha-loader 的目标是在 Webpack 里集成测试,比如边开发边测试,并不是我想要的。我想要的是:打包测试内容,整合测试框架,方便用户在 CI 系统里集中进行测试。

所以我真正需要的,其实是:

  1. 创建一个独立的 webpack 配置文件,用来打包单元测试
  2. 打包后执行测试,返回测试结果

基本上,今天大半天的工作是白费了。mocha-loader 的作者应该把目的写在 README 里的……

分类
分享

GitChat: 使用 webpack 开发企业官网

最近我厂官网改版,我尝试用 Webpack 重建了开发工具链,效果不错,配置代码少了很多,逻辑更加简单清晰。我觉得值得拿出来分享一下。

文章已经发布,慢慢写了将近5w字,干货很多,覆盖面很广,欢迎大家前去阅读:升级工具链吧!使用 Webpack 开发企业官网。感谢大家的支持。

交流应该会通过直播进行,暂定7月中吧,斗鱼直播间:douyu.tv/meathill。

分类
js 技术

最近折腾 @babel/preset-env 的一些小心得

近来厂里的项目越来越多,代码共享必不可少。我现在采取的方案是:

  1. 把公共组件拿出来,开一个新仓库
  2. 使用 webpack 进行打包编译,libraryTarget: 'umd'
  3. 将打包编译的代码一起提交到仓库
  4. 使用 npm i <owner>/<repo> -S 安装依赖,因为我厂的仓库均为私有,所以不能发布到 NPM

这套方案简单好用,实操效果良好。接下来我希望优化打包结果,于是研究了打包配置项,下面是我的一点心得。

分类
前端

近期用 webpack-dev-server 作代理的一些经验

如今前端开发使用 webpack-dev-server 作为本地服务器已经是基本配置,加上 proxy 功能可以很好的应对 SSL、跨域、线上环境切换等需求。Vue CLI 3 里也做了相应的集成,用起来很方便。

分类
vue

Vue 小贴士

书说简短:

  1. 使用 Vue + Webpack 开发
  2. 使用 CDN 加载依赖
  3. 在开发阶段尽量不要使用压缩的文件,一边取得尽量全面的错误信息