前端最常用的打包工具webpack(三)-兼容性处理

这是重新学习webpack的第三篇文章,之前我也写过一篇关于webpack的文章。问题是过去快半年了,我已经将webpack忘得差不多,回头一看那篇文章完全是一头雾水,也没有办法,那个时候我才刚刚开始写前端方面的博客,对于知识梳理、文字表达都有一些欠缺,啪啪啪一下扔出来几千字,全是重点,没有任何过渡性的语言,看个一会就没什么兴趣。

综上所述,本次决定给webpack写一个比较详细的系列文章,目的是如果我半年后又忘记了webpack的具体内容,再来翻阅文章,不会像这次一样一头雾水。

前景提要

在之前的那篇文章中,我学到了如何将css、js、scss、html通过webpack进行打包,而本篇文章,就着重讲解如何处理js、css的兼容性,以及如何将项目运行在webpack内置的服务器上。


1. 兼容性

1.1 css兼容性

css因为每个浏览器实现的方式不同,而且不同的浏览器还有各自的私有属性:

常用的前缀有:

  • -moz代表firefox浏览器私有属性
  • -ms代表IE浏览器私有属性
  • -webkit代表chrome、safari私有属性
  • -o代表opera私有属性

例如transform:rotate(-3deg)这个css属性,兼容性写法就应该是:

-webkit-transform:rotate(-3deg); /* 为Chrome/Safari */
-moz-transform:rotate(-3deg); /* 为Firefox */
-ms-transform:rotate(-3deg); /* 为IE */
-o-transform:rotate(-3deg); /* 为Opera */
transform:rotate(-3deg);

试想一下,如果每一条CSS3的语句都要写成这样,那几乎不用玩了,不光你要一条条的查找该CSS属性是否存在兼容性问题,你还必须写上这些私有属性语句。

虽然现在有些网页能够帮助你将CSS语句进行转换,但是一个页面中可能有非常多的.css文件,你要一个一个的去转换肯定是不现实的。

这个时候webpack通过插件,可以自动帮你添加这些兼容性语句,你只需要专心写css相关的样式就可以了。

1.2 js兼容性

因为有些浏览器比如IE浏览器不识别ES5之后的语法,而ES6里面有太多的便利的写法,不仅引入了箭头函数解决了历史遗留的this指针问题,还引入了class、promise这些十分方便的新特性,你总不可能不用ES6的语法再回去写ES5的语法吧?

而webpack有插件可以直接将ES6后的语法转换为ES5的语法,你只需要进行配置一下,你就可以放心的书写ES6的语法,而不用担心兼容性问题,所有的兼容性问题插件会帮助你解决。

相信看到这里,你一定对本篇文章所要讲述的内容有一定的了解,那么我们就开始吧!


2. CSS

2.1 提取CSS到单独文件

之前我们一直将CSS放在.js中,但是这样无疑会增大.js文件的体积,而且有些浏览器对js文件的解析速度还没有css文件的解析速度快,所以我们需要把样式文件单独提取出来。

需要的插件mini-css-extract-plugin

npm install mini-css-extract-plugin --save-dev

配置也很简单:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// 在css loader中用MiniCssExtractPlugin.loader替代style-loader
{
  // 用正则表达式匹配文件类型,下面就是匹配以.css结尾的文件,并且将它们使用下面的loader解析。
  test: /\.css$/,
  use: [
    MiniCssExtractPlugin.loader,
    // 将css文件编程CommonJs模块加载到js中,里面内容是样式字符串
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          // 浏览器兼容性处理
          plugins: ["postcss-preset-env"],
        },
      },
    },
  ],
},

// 在plugins中引入插件
new MiniCssExtractPlugin(),

这样我们打包项目中的样式文件就会单独的放在一个.css文件中。当然我们也可以通过配置插件的filename属性命名打包后的.css文件。

new MiniCssExtractPlugin({
  // 对输出的样式文件重命名
  filename: "css/style.css",
}),

2.2 兼容性处理

这里需要使用到PostCSS

PostCSS是一个用来处理项目中CSS文件的工具,它具有非常多的功能,同时拥有大量插件,可以实现处理CSS兼容性问题,处理CSS重复代码问题等等一系列的问题。

因为我对PostCSS也没有深入研究,所以这里只是讲解一下它如何处理CSS各个厂商的私有属性。

首先我们需要引入两个包:

npm install postcss-loader postcss-preset-env --save-dev

package.json文件中添加下面的代码,当然也可以单独提取出来做一个文件,文件名要命名为:.browserslistrc

下面代表适配浏览器的版本,关于更多配置可以到browserslist。进行查看,而我这里直接拿了vue项目默认的兼容性配置。

"browserslist": [
  "> 1%",
  "last 2 versions",
  "not dead"
]

然后修改webpack.config.js中的配置。

// 在loader中配置
{
  // 用正则表达式匹配文件类型,下面就是匹配以.css结尾的文件,并且将它们使用下面的loader解析。
  test: /\.css$/,
  use: [
    MiniCssExtractPlugin.loader,
    // 将css文件编程CommonJs模块加载到js中,里面内容是样式字符串
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          // 浏览器兼容性处理
          plugins: ["postcss-preset-env"],
        },
      },
    },
  ],
},

到这里再通过webpack打包:

打包前:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  display: flex;
  backface-visibility: hidden;
}

打包后:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  display: flex;
  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
}

可以看到PostCSS自动为我们做了兼容性处理。

2.3 压缩CSS

可以看到我们上面的CSS虽然经过了打包,但是没有进行压缩,所谓的压缩就是去掉代码的格式,让代码紧挨在一起,从而减小代码的体积。

npm install css-minimizer-webpack-plugin --save-dev

使用也非常简单:

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

// 引入插件
new CssMinimizerPlugin(),

重新进行打包,会发现css文件已经被压缩:

*{padding:0;margin:0;box-sizing:border-box;display:flex;-webkit-backface-visibility:hidden;backface-visibility:hidden}

3. js

3.1 Eslint

代码风格检测,因为JavaScript语言为脚本语言,所以写法非常的自由,在团队协作开发时,可能你用的是双引号,我用的是单引号,你句尾加;号,而我句尾不加。

这些场景非常常见,有时候会因为代码样式问题造成合代码时产生大量冲突,Eslint的出现就是为了解决团队代码风格不一致的问题,它可以通过配置文件让你强制使用双引号或者单引号、句尾加;或不加;。让一个项目的代码运用一种风格进行编写。

同时Eslint还会检测出部分代码中可能暗藏BUG的语句。

引入Eslint的目的是为了统一代码风格,提高团队效率,而且现在在vscode上面也有Eslint插件(WebStorm上自带Eslint插件)可以在保存的时候根据规则进行自动修复。而我其实对于Eslint是非常喜爱的。

引入:

npm install eslint-webpack-plugin eslint --save-dev

配置:

const ESLintPlugin = require("eslint-webpack-plugin");

new ESLintPlugin({
  // 自动修复代码
  fix: true,
}),

这里配置就完成了,你可以直接在项目中输入命令:

eslint --init

生成配置文件,它可以选择3个大公司的Eslint规则,分别是:

在过去Airbnb用的是非常多的,但是我其实更喜欢使用prettier,因为prettier更接近我平时写代码的风格,而且最近使用prettier的越来越多。

prettier使用

下载:

npm install eslint-config-prettier eslint-plugin-prettier prettier --save -dev

在项目根目录中创建.eslintrc.js文件,写入下面的代码。

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: ["prettier", "plugin:prettier/recommended"],
  parserOptions: {
    ecmaVersion: 12,
    sourceType: "module",
  },
  rules: {},
};

3.2 兼容性处理

正如上面所说,有些浏览器不认识ES6的语法,所以我们需要对这些代码做一些兼容性处理。

如果我们有下面的js代码:

import "./src/style.css";

const promise = new Promise((resolve) => {
  setTimeout(() => {
    resolve(2);
  });
});

promise.then((req) => {
  console.log(req);
});

可以看到我们这里不光用了ES6的const还用了Promise,最终的打包结果是:

!function(){"use strict";new Promise((e=>{setTimeout((()=>{e(2)}))})).then((e=>{console.log(e)}))}();

Promise没有经过兼容性处理,这个时候我们就需要引入下面的包:

npm install -D babel-loader @babel/core @babel/preset-env core-js

配置:

{
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    {
      loader: "babel-loader",
      options: {
        // 预设:指示babel做怎么样的兼容性处理。
        presets: [
          [
            "@babel/preset-env",
            {
              corejs: {
                version: 3,
              },
              // 按需加载
              useBuiltIns: "usage",
              // 需要适配的最低版本
              targets: {
                chrome: "60",
                firefox: "60",
                ie: "9",
                safari: "10",
                edge: "17",
              },
            },
          ],
        ],
      },
    },
  ],
},

再进行一次打包,看一下最后我们打包的js文件,发现多了很多代码,这是因为将Promise转化成了ES5的形式进行实现。

4. devSever

在之前的项目中,我们的目录结构最重要的两个文件夹:

  • build:打包后项目的代码。
  • src:项目的源代码。

image-20210207162916561

我们最好将项目的源代码放在src中进行统一管理,但是我们运行的项目是build目录中最终打包后的项目,如果我们源代码发生了改变,我们就必须要手动执行一次打包命令进行重新打包,不然build目录下依然是上次打包后的结果。

为了实现项目热更新,我们需要用到webpack-dev-server

它实现了项目的热更新,需要注意的是,它的操作是在内存中进行完成,并不会输出打包文件,首先进行下载:

npm install webpack-dev-server --save-dev

webpack.config.js中增加配置:

devServer: {
  // 项目构建后的路径
  contentBase: resolve(__dirname, "build"),
  // 启动gzip压缩
  compress: true,
  // 端口号
  port: 3000,
  // 自动打开浏览器
  open: true,
},
  • contentBase:项目构建后的路径。
  • compress:gzip压缩。
  • port:端口号。
  • open:打开浏览器,默认为false。

配置完毕后输后在终端中输入:

webpack serve

等待一会,发现会打开一个新窗口。

image-20210207163837817

新窗口中就可以看到之前的项目。

这个时候只要代码进行了改动,devSever就会自动帮我们再进行打包、刷新浏览器等操作。

5. 最后

到这里为止,webpack的基础内容几乎已经全部学习完毕,经过本次的学习,我学到了如何处理CSS和JS的兼容性问题,同时我也学到了如何通过webpack打开一个服务器。

但是webpack的学习之旅还没有结束,我们只是会了基础的webpack配置,还有关于项目优化的配置我们还没有进行学习,比如如何优化打包速度,如何加快项目启动速度,如何加快热更新速度,这些都影响着我们实际开发中的效率。