分类
前端工具链

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 实现界面了。

分类
前端工具链

升级 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' 即可解决。

分类
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 也很好用,可惜不能直接用
分类
前端工具链

解决“Error: Rule can only have one resource source (provided resource and test + include + exclude)”

又有一台服务器到期,不想续了,所以把东西往另一台服务器上搬。其中有一个小服务,用来存储 CI 测试失败的截图。里面有用到 font-awesome,但只用一个图标,太浪费。所以这次就顺手换成了 bootstrap-icons,然后顺便更新依赖,结果,再编译的时候,就报错:

ERROR  Error: Rule can only have one resource source (provided resource and test + include + exclude) in {
   "exclude": [
     null
   ],
   "use": [
     {
       "loader": "/Users/meathill/Projects/mini-store-admin/node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js",
       "options": {
         "cacheDirectory": "/Users/meathill/Projects/mini-store-admin/node_modules/.cache/babel-loader",
         "cacheIdentifier": "219fb45a"
       },
       "ident": "clonedRuleSet-38[0].rules[0].use[0]"
     },
     {
       "loader": "/Users/meathill/Projects/mini-store-admin/node_modules/babel-loader/lib/index.js",
       "options": "undefined",
       "ident": "undefined"
     }
   ]
 }

非常诡异,按照错误栈点进去,从代码可以推断是生成的 webpack config 有问题,在 babel-loader 配置里既包含 resource 又包含 exclude。但是,这个项目是通过 @vue/cli 创建的,所以它的配置也是 @vue/cli-service 自动生成的,我并没有修改过。而且只有这个项目有问题,其它项目,同样使用 @vue/cli 创建,但是没有更新依赖,就没问题。

Google 之,有一些关于这个错误的讨论,但几乎都是用户自己写 webpack.config.js 没写好出问题。有人建议 rm -rf node_modules & rm package-lock.json & npm i,即重装所有依赖,我试了两次,也不行。

开始尝试、推翻、再尝试、再推翻。后来怀疑到 webpack ,在 package-lock.json 里查找之,发现安装的版本竟然是 5.1.0,而没有更新过依赖,可以正常编译的项目里都是 4.x。那基本可以确认了。

  1. 先删掉 node_modulespackage-lock.json
  2. 手动在 package.jsondevDependencies 里添加 "webpack": "^4.44.2"
  3. 重新安装全部依赖: npm i
  4. 尝试编译,npm run build,发现问题解决

总结

我猜问题是这样的:某些新版本的库要求 webpack@5,更新依赖时,根据依赖选择的规则,就以 webpack@5 作为主依赖安装。然而 @vue/cli 依赖 webpack@4,它自带的 webpack 配置无法兼容 webpack@5 ,于是就报错,不能继续编译。如果你也在使用 @vue/cli,那么请不要贸然升级 webpack@5。

分类
vue

升级 Vue@2 项目到 Vue@3

这篇主要是笔记。(我估计会是第一篇,因为只迁移了一个项目)

1. 安装新包

只记录必须重装的:

npm i vue@3 vue-loader@16.0.0-beta.8 vue-router@4.0.0-beta.13 @vue/compiler-sfc

2. 修改 Webpack 配置

// v2
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// v3
const {VueLoaderPlugin} = require('vue-loader');

// for DefinePlugin
{
  plugins: [
    new DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false,
    }),
  ],
}

3. 修改入口文件

没有 new Vue({}) 了,取而代之的是 Vue.createApp({}),后者还支持 tree-shaking。

也不需要注册 Vue-router 了,直接 app.use(router) 就好。所以传统的入口文件就要修改为:

// v2
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@/styl/index.styl';
import router from './router';

Vue.use(VueRouter);

Vue.config.productionTip = false;

new Vue({
  router,
  ...App,
}).$mount('#app');

// v3
import {createApp} from 'vue';
import App from './app';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@/styl/index.styl';
import router from './router';

const app = createApp({
  ...App,
});
app.use(router);
app.mount('#app');

4. 修改 router

Vue-router 的变化很大,建议大家好好看看 迁移手册。就我厂这个项目而言,主要是三个变化:

  1. 使用支持 tree-shaking 的函数 createRouter
  2. 修改 history: createWebHistory()
  3. 使用渲染函数 h 替换之前渲染方式
// 加载方式
import {h} from 'vue';
import {
  createRouter,
  createWebHistory,
  createWebHashHistory,
  RouterView,
} from 'vue-router';

const routes = [
  {
    path: '/',
    name: 'home',
    component: {
      // vue-router v3
      render(createElement) {
        return createElement('router-view');
      }

      // vue-router v4
      render() {
        return h(RouterView);
      },
    },
    children: components,
  },
  // ....
];

const router = createRouter({
  // vue-router v3
  mode: process.env.NODE_ENV === 'production' ? 'history' : 'hash',
  // vue-router v4
  history: process.env.NODE_ENV === 'production'
    ? createWebHistory()
    : createWebHashHistory(),
  scrollBehavior: (to) => {
    if (to.hash && !/^#/.test(to.hash)) {
      return {selector: to.hash};
    }
    // 这里有个小改动,x => left, y => top,简单提一下
    return {top: 0};
  },
  routes,
});

5. 自定义组件 v-model 修改

  • prop: value => modelValue
  • event: input => `update:modelValue`

6. 一些小修改

  • beforeDestroy => beforeUnmount

7. createApp 与 Application,与 Component

v2 时,我们可以通过 new Vue({}) 初始化 Vue 实例。这个阶段,Vue 默认有一个全局对象 + 若干个实例,除了 local 的,就是全局的。

v3 时,引入了 Application(应用)的概念,在全局和组件之间,增加了一个新的层级。这样一来,我们就可以在同一个 Web 产品中,使用 Application 来划分命令、组件、mixins 的范围。应该会增加代码的强壮程度(虽然我暂时还没用到)。

不过,迁移代码的时候,也要注意。以前我们可能 new 一个实例,调用它的 methods;现在不行了,要这样做:

// v2
const ins = new Vue({});
ins.doSomething();

// v3
const app = createApp({});
const vm = app.mount('$el');
vm.doSomething();

8. 新的响应式 API

v3 最大的变化就是重构了响应式实现,所以新增了不少响应式 API。同时,也会检查开发者的代码,如果发现不需要响应式的地方用到响应式对象,就会提示开发者,因为响应式会增加系统开销。

这个时候可以用 markRawtoRaw 方法来修改对象,撤销之前附加在上面的响应式属性,提高访问效率。

其它 API 还很多,后面慢慢更新吧。

9. Devtool 和 SourceMap

遗憾的是,目前 Vue Devtool 无法检测到 Vue。老项目的 SourceMap 也完全不生效,无法正常对 SFC 进行 debug。

分类
前端工具链 技术

初试 Webpack 5,解决合并 CSS 时多余的 JS

在长文分享《GitChat: 使用 Webpack 开发企业官网》中,我使用 Webpack 重构了官网开发工具链,效果很好,现在的开发效率也很高。

当时遗留下来一个问题:

  1. 我会把所有页面的 CSS 打包到一起。因为 CSS 尺寸不大,打包到一起利用浏览器缓存,可以改善后续页面的打开速度。
  2. 打包+抽取 CSS+合并,使用 mini-css-extract-plugin,配合 splitChunks。这里遵循的是 官方文档
  3. 打包完成后,除了包含所有样式的 screen.css,还会生成 screen.js,里面包含 webpack 模块的初始化代码,只有一行,几十个字节,但是很重要,必须在其它模块前先完成加载。

于是我就面临一个选择:

  1. 留着这个东西,会略微影响网页打开速度。因为它毕竟是个 JS 文件,要单独加载和运行。
  2. 想办法去掉它,比如利用 html-webpack-plugin 提供的各种钩子,写个插件,把它的内容提取出来,放进 html 或者跟 app.js 合并,等等。但是这个时机很难找,我尝试过一段时间,无果。

最后综合考虑成本和收益,以及看到这个 issue:https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151 之后,我决定再等等,webpack 5 的时候再说。

最近 Webpack 5 终于发布了,我就来试试升级解决这个问题。

升级 Webpack 5

首先升级 Webpack@5 和 webpack-cli@4。新版本虽然底层变化很大,API 层面还是尽量保持了兼容性,所以配置文件可以不改或者小改(理论上)……果然编译就报错了,错误信息很扯:Error: Can't resolve './src',非常莫名其妙。Google 半天无果,后来我突然想起,假如 Webpack 配置信息没加载成功,那么它会默认使用 ./src/index.js 作为入口文件,是不是这个问题呢?

然后搜了半天,没有 dump configuration 的选项,只好仔细看文档。迁移指导里并没有关于配置文件的内容。那就看文档,然后发现,之前 Webpack@4,配置文件可以输出 Object、Promise、或者函数,所以项目的配置文件就是直接输出的 Promise;如今,虽然标题仍然是“Exporting a Promise”,但实际上 module.exports 导出的是函数,只是函数的返回值可以是 Promise。

这里嫌疑很大,所以我就试着改了一下,用函数包裹 Promise,果然可以了。

移除不必要的 screen.js

我会把所有样式都打包到 screen.css 里,这是从 HTML5 boilerplate 学到的。然后 Webpack 就会生成 screen.js,这是个多余的文件,只有坏处,前面说过。

我以为 Webpack@5 之后这个问题就自然解决了,结果看了一眼,还有,只好继续寻找解决方案。之前的关键词忘记了,issue 也没关注,所以多花了不少时间。所幸最终找到了:https://github.com/webpack/webpack/issues/7300#issuecomment-702840962

  1. 升级 webpack@5,webpack-cli@4,自不用说
  2. 升级 mini-css-extract-plugin@1,新版本包含了需要的补丁
  3. 如下修改代码
{
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          type: 'css/mini-extract', // 重点在这里
          chunks: 'all',
          // If you need this uncomment
          // enforce: true,
        },
      },
    },
  },
}

然后重新编译,screen.js 就不见了,非常爽。

分类
前端

Webpack 5 发布,Chrome 86 开始支持本地文件系统

早上起来日常刷技术新闻,看到两个对我和我厂影响比较大的消息,简单写几句。

Webpack 5 发布

Webpack 5 于今天(北京时间10月11日,美国时间10月10日)发布。这是个大版本更新,会有很多破坏性变更。所以不要轻易升级,否则可能遭遇各种问题。不过,对于像我这种三天两头主动升级依赖的人来说,是否可以平滑升级还未为可知。

这次的升级主要有以下几点变化:

  • 使用持久缓存提升性能
  • 通过替换更好的算法和缺省值,提升长期缓存的效果
  • 使用更好的 Tree Shaking 算法和代码生成方式,减少打包后的提及
  • 提升 web 平台的兼容性
  • 在不引入破坏性变更的前提下,清理掉为实现 v4 功能而遗留下的奇怪的内部架构
  • 现在的破坏性变更是为将来实现更多的功能打好基础,让我们可以在 v5 版停留尽可能长的时间
  • (我加的)多页面 css 合并的时候,不再需要 all.js

更详细的内容大家请移步官网了解:Webpack 5 release (2020-10-10)。英语苦手的同学稍微等两天,估计中译版和各种解读版也会很快问世。

我只有两个建议:

  1. 尽快升级你的项目到 webpack 5
  2. 不要再学/用以前的版本了

Chrome 86 开始支持本地文件系统

很久很久以前,我在上一家公司做创业项目肉大师(Web 创作工具),不小心踏入了 FileSystem API 这个大坑。还留下一篇长文《HTML5的File API应用》,可能是为数不多的中文资料。

时隔八年,如今文件系统 API 终于有了比较靠谱的实现,并且被 Chrome 正式支持。一般来说,Chrome 的统治地位会帮助这个 API 成为事实标准,所以如果你对操作本地文件有需求,那么就可以开始使用这个 API 了,将来它会慢慢普及到其它浏览器上。

简单来说,这个 API 允许用户选择若干文件或者目录,相当于用户主动授权某些文件或目录给当前网站,然后 JS 就可以从文件里读内容,或者把内容写入文件。当然,从安全角度出发,网页不能任意访问文件,一定要用户主动选择。

对于我厂来说,这意味着 QA 产品可以更容易的编辑、保存文件,可以大大提升用户体验。一些 Web 工具也可以直接保存内容到用户本地,感觉网页生态更强大了。

更详细的内容可以阅读这两篇文章:

总结

学无止境,勤为径苦作舟吧。

分类
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 这样,就再开一篇。