Webpack5+vscode搭建kintone开发环境(六)css、less、scss、图片支持

cybozu发表于:2021年01月07日 14:19:13更新于:2021年07月28日 14:31:23

目录

第一篇:初始化项目
第二篇:代码规范
第三篇:Webpack 基本配置
第四篇:开发环境设置
第五篇:生产环境设置
第六篇:css、less、scss、图片支持
第七篇:IE11 兼容
第八篇:支持 React
第九篇:支持 Typescript>
第十篇:命令行工具

css

接下来我们说一下样式文件处理方案,由于 webpack 只编译 .js 文件,它默认是不支持直接处理 .css 、 .less 或 .scss 文件的。
那么是不是意味着我们只能在 js 里面通过 style 属性来间接使用 css?并不是!

安装

要处理 .css 文件我们需要安装 style-loader 和 css-loader

npm install style-loader css-loader -D

对于 .css 为后缀的文件,webpack 会先调用 css-loader 去解析这个文件,遇到 @import 等语句就引入相应的文件。最后计算生成 css 字符串,再调用 style-loader 生成 style 标签。

loader 是有顺序的,我们需要先解析 css 再生成 style,因此,style-loader 要被放在 css-loader 之前。(webpack loader 的执行顺序是从后往前)

由于所有的环境下都需要使用 css 解析,因此解析代码最适合放在 webpack.common.js 中。

module.exports = {
    // other...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              sourceMap: isDev,
              importLoaders: 0,
            },
          },
        ],
      },
    ]
  },
}
  • test:匹配规则,这里匹配了后缀名 css 的文件。

  • use:针对 test 匹配的文件,需要采用哪种 loader。我们采用了 style-loader 和 css-loader 来共同处理,所以要用数组的方式来写。

    • css-loader 我们需要一些自定义的设置,这里写成了 object 的形式:

    • sourceMap:生产环境关闭,开发环境开启。

    • importLoaders:指定在 css-loader 处理前使用的 laoder 数量,之后的 less、scss 需要先做 css 转换,到时候这个值要变成 1.


使用

在 src 目录下新建 app.css,并输入:

.app {
  text-align: center;
  background-color: cyan;
}

修改 index.js :

import './app.css'
kintone.events.on('app.record.index.show', (event) => {
  const root = kintone.app.getHeaderSpaceElement()
  root.innerHTML = '<div class="app"><h1>hello, kintone!</h1></div>'
  return event
})

由于 index.js 本身就是 entry 中指定的入口,所以 webpack 会按照 import 里面的内容自动加载 css 文件并加以解析。

让我们运行 start 命令来看看效果。

npm run start


分离 & 压缩

运行

npm run build

你会发现 css 内的内容被整合进了 app.${hash}.js,而且 css 中的注释也会原封不动地写了进去。
在开发环境下没什么关系,但是在生产环境也是这样就不友好了,它会造成 js 文件过大从而导致加载速度变慢。
kintone 本身也支持自定义 css 文件,所以在生产环境下需要对 css 进行分离压缩。

我们使用 mini-css-extract-plugin 来分离 css,使用 css-minimizer-webpack-plugin 来压缩。

npm install mini-css-extract-plugin css-minimizer-webpack-plugin -D

在 webpack.common.js 处,我们需要在 style-loader 处加入如下判断:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  //others
  module: {
    rules: [
      {
        //others
        use: [
          isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
          //others
        ],
      },
    ],
  },
}

在 webpack.prod.js 处,加入以下代码:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = merge(common, {
  //others
  plugins: [
    //others
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[name].[contenthash:8].css',
    }),
    //others
  ],
  optimization: {
    minimizer: [
      //others
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true },
            },
          ],
        },
      }),
    ],
    //others
  },
})
  • MiniCssExtractPlugin 放在 plugins 里面,css 输出文件名规则和 js 靠拢,顺便分离出 chunk。

  • CssMinimizerPlugin 放在 optimization.minimizer 中,通过 discardComments: { removeAll: true }, 在压缩的同时移除掉所有的注释。

重新 build 一下看看效果。


去除未被使用的 css(慎用)

我们使用 purgecss 来实现这一需求,但要注意的是,有 style 式样的第三方包需要设置 whitelist

我们先安装它及路径查找利器 node-glob

npm install purgecss-webpack-plugin glob -D

然后在 webpack.prod.js 中增加以下代码:

const { resolve } = require('path')
const glob = require('glob')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')

module.exports = merge(common, {
  //others
  plugins: [
    //others
    new PurgeCSSPlugin({
      paths: glob.sync(`${resolve(__dirname, '../src')}/**/*.{js,jsx,ts,tsx,scss,less,css}`, { nodir: true }),
    }),
    //others
  ],
})
  • glob 用来查找文件路径的,找到 src 下后缀为 .js、.tsx、.css、.less、.scss 的文件路径并以数组形式返给该插件。

  • nodir 去除文件夹的路径,加快处理速度。

大家可以在 app.css 中加一些未被使用的代码,重新 build 一下看看效果。


less & scss

less 和 scss 扩展了 css 的语法,只要能把 less 或 scss 转译成 css,那么我们就可以通过现有配置来实现对它们的支持。
对于 less,我们需要安装 less 和 less-loader :

npm install less less-loader -D

对于 scss,我们需要安装 node-sass 和 sass-loader :

npm install node-sass sass-loader -D

基本的配置思路是在 rules 中匹配 less/scss,并在 css-loader 加载前完成转化。
只是这样一来,css-loader 配置必定重复出现 3 次,显得十分冗余,需要把这部分内容抽取出来。

在 webpack.common.js 中修改如下:

const cssLoaders = (preNumber) => [
  isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: {
      sourceMap: isDev,
      importLoaders: preNumber,
    },
  },
]

module.exports = {
  //others
  module: {
    rules: [
      {
        test: /\.css$/,
        use: cssLoaders(0),
      },
      {
        test: /\.less$/,
        use: [
          ...cssLoaders(1),
          {
            loader: 'less-loader',
            options: {
              sourceMap: isDev,
            },
          },
        ],
      },
      {
        test: /\.scss$/,
        use: [
          ...cssLoaders(1),
          {
            loader: 'sass-loader',
            options: {
              sourceMap: isDev,
            },
          },
        ],
      },
    ],
  },
}
  • cssLoaders 这个函数接受一个 preNumber 参数,该参数决定了在 css-loader 加载前需要加载几个其他的 loader

  • less 加载 less-loader,scss 加载 sass-loader,它们的 sourceMap 和 devtool 一致。

添加一个 less/scss 的文件看看 build 效果把。


图片和字体文件处理(慎用)

kintone 没有自定义字体或图片功能,折中的解决办法是把本地资源打包成 base64 插入到 js 文件中。
但要注意的是大量的本地资源会导致我们的成品文件急剧变大,所以需要谨慎使用。
我们用 url-loader 来处理本地资源文件。

npm install url-loader -D

然后在 webpack.common.js 中继续在 modules.rules 下添加以下代码:

module.exports = {
  //others
  module: {
    rules: [
      //others
      {
        test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/],
        use: 'url-loader',
      },
      {
        test: /\.(ttf|woff|woff2|eot|otf)$/,
        use: 'url-loader',
      },
    ],
  },
}

iconfont下载一个图片并修改 index.js:

import my from './my.png'
kintone.events.on('app.record.index.show', (event) => {
  const root = kintone.app.getHeaderSpaceElement()
  root.innerHTML = '<div><p>hello kintone!</p><img src="' + my + '"/></div>'
  return event
})

看看 build 的效果吧。