css样式文件(如.css/.less/.styl/.scss)写完之后需要有ccs相关的加载插件才能编译成最终的css文件。

1、新增一个css文件

新增一个index.css文件

body {
  margin: 0;
  background-color: pink;
}

aaa.js中引入

import './bbb.js'
console.log("aaaa js maomao")

require("./index.css")

运行:

npm run dev

此时会发现有错误信息:

ERROR in ./src/index.css 1:5
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> body {
|   margin: 0;
|   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
 @ ./src/aaa.js 4:0-22

webpack 5.21.2 compiled with 1 error in 233 ms
ℹ 「wdm」: Failed to compile.

显示需要合适loader来加载index.css文件。

2、添加合适的loader配置

添加webpack配置:

module.exports = {
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.css$/,//匹配到css结尾的文件,加载css-loader,
        //css-loader负责解析@import语法,将多个css文件合并成一个
        //style-loader负责把css文件插入到<head>标签中
        //loader的特点:功能单一
        //loader的用法:
        //use:"css-loader"字符串形式只能用一个loader
        //use:[]数组形式可以用多个loader
        //多个loader时,加载顺序是从后往前加载(从右向左执行)
        use: ["style-loader", "css-loader"]
      }
    ]
  }
}

这里添加了两个loader,分别是style-loadercss-loader(需先安装这两个loader);

他们的加载顺序是先用css-loader合并css文件,然后用style-loader把css文件插入html文件里。

3、修改css代码插入的顺序

在模版文件index.html中插入一段样式,修改背景为红色:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body{
      background:red
    }
  </style>
</head>
<body>
  <!-- 模版,此处插入js脚本 -->
  <div>我是毛毛</div>
</body>
</html>

然后运行,发现并未生效。

原因是编译后的文件中,把css编译结果插到了代码<style>样式的后面。

按照css的优先级规则,下面的样式覆盖了上面的样式。

<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title>
<style>body{
      background:red
    }
</style>
<style>body {
  margin: 0;
  background-color: pink;
}
</style>
</head>
<body><!-- 模版,此处插入js脚本 --><div>我是毛毛</div><script src="bundle.796a847a.js?796a847a739e67336a8d"></script></body><div id="translate-button" style="background-color: white;"</div></html>

如果你需要将代码里的样式优先级提高,就需要修改webpack将style-loader插入的css放到<head>标签的最上面。

展开style-loader配置,可以修改css代码插入<head>的顺序。

        use: [{
          loader: "style-loader",
          options: {
            insertAt: "top",//将当前loader添加到<head>标签内容的最上面
          }
        }, "css-loader"]

运行:npm run dev

发现报错了:

ERROR in ./src/index.css
Module build failed (from ./node_modules/style-loader/dist/cjs.js):
ValidationError: Invalid options object. Style Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'insertAt'. These properties are valid:
   object { injectType?, attributes?, insert?, base?, esModule?, modules? }
    at validate (/Users/maomao/Documents/demo/h5/mm_webpack/node_modules/style-loader/node_modules/schema-utils/dist/validate.js:98:11)
    at Object.loader (/Users/maomao/Documents/demo/h5/mm_webpack/node_modules/style-loader/dist/index.js:25:28)
 @ ./src/aaa.js 4:0-22

webpack 5.21.2 compiled with 1 error in 634 ms
ℹ 「wdm」: Failed to compile.

原因是:

  • webpack4.0insertAt已经被废弃,现在的api是insert, 这是一个函数。

特别鸣谢:sunshine_uniq

正确的配置如下:

        use: [{
          loader: "style-loader",
          options: {
            //将当前loader添加到<head>标签内容的最上面
            insert: function (element) {
              var parent = document.querySelector('head');
              var lastInsertedElement = window._lastElementInsertedByStyleLoader;
              if (!lastInsertedElement) {
                parent.insertBefore(element, parent.firstChild);
              } else if (lastInsertedElement.nextSibling) {
                parent.insertBefore(element, lastInsertedElement.nextSibling)
              } else {
                parent.appendChild(element)
              }
            }
          }
        }, "css-loader"]

运行发现代码中的样式已生效,查看编译后的文件:

发现css文件的样式已经被加载到了最上面。

<html lang="en"><head><style>body {
  margin: 0;
  background-color: pink;
}
</style>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title>
<style>
body{
      background:red
    }
</style>
</head>
<body><!-- 模版,此处插入js脚本 --><div>我是毛毛</div><script src="bundle.01980114.js?01980114afe45003ca7e"></script></body><div id="translate-button" style="background-color: white;"></div></html>

4、加载 less、stylus、sass

less

安装:

npm install less less-loader -D

stylus

安装:

npm install stylus stylus-loader -D

sass

安装:

npm install node-sass sass-loader -D

webpack配置:在最后加入stylus-loader

        use: [{
          loader: "style-loader",
          options: {
            //将当前loader添加到<head>标签内容的最上面
            insert: function (element) {
              var parent = document.querySelector('head');
              var lastInsertedElement = window._lastElementInsertedByStyleLoader;
              if (!lastInsertedElement) {
                parent.insertBefore(element, parent.firstChild);
              } else if (lastInsertedElement.nextSibling) {
                parent.insertBefore(element, lastInsertedElement.nextSibling)
              } else {
                parent.appendChild(element)
              }
            }
          }
        }, 
        "css-loader",
        "stylus-loader"
      ]

运行:npm run dev

发现报错了:

webpack 5.21.2 compiled with 1 error in 61 ms
ℹ 「wdm」: Failed to compile.
ℹ 「wdm」: Compiling...
✖ 「wdm」: assets by status 4.94 KiB [cached] 1 asset
asset index.html 356 bytes [emitted]
cached modules 101 bytes (javascript) 997 bytes (runtime) [cached] 6 modules
./src/index.styl 392 bytes [built] [1 error]

ERROR in ./src/index.styl 1:5
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> body {
|   margin: 0;
|   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
 @ ./src/aaa.js 4:0-23

webpack 5.21.2 compiled with 1 error in 47 ms
ℹ 「wdm」: Failed to compile.

原因是原来的webpack配置错误,

应该在rules下新增.styl的样式加载配置:


module.exports = {
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.styl$/,//匹配到styl结尾的文件,加载stylus-loader,
        //css-loader负责解析@import语法,将多个css文件合并成一个
        //style-loader负责把css文件插入到<head>标签中
        //loader的特点:功能单一
        //loader的用法:
        //use:"css-loader"字符串形式只能用一个loader
        //use:[]数组形式可以用多个loader
        //多个loader时,加载顺序是从后往前加载(从右向左执行)
        use: [{
          loader: "style-loader",
          options: {
            // insert: "top",//将当前loader添加到<head>标签内容的最上面

            insert: function (element) {
              var parent = document.querySelector('head');
              var lastInsertedElement = window._lastElementInsertedByStyleLoader;
              if (!lastInsertedElement) {
                parent.insertBefore(element, parent.firstChild);
              } else if (lastInsertedElement.nextSibling) {
                parent.insertBefore(element, lastInsertedElement.nextSibling)
              } else {
                parent.appendChild(element)
              }
            }
          }
        },
          "css-loader",
          "stylus-loader"
        ]
      },
    ]
  }
}

运行成功。

其他的less和sass也是一样的,安装对应的加载插件之后,将test匹配的文件后缀修改成对应的文件后缀,

然后将最后的"stylus-loader"改为"less-loader""sass-loader"

5、抽离CSS样式

安装抽离css样式的插件:mini-css-extract-plugin

npm install mini-css-extract-plugin -D

webpack中添加如下配置:

let MiniCssExtractPlugin = require("mini-css-extract-plugin")//抽离css 插件
module.exports = {
  plugins: [//存放所有插件
    new MiniCssExtractPlugin({
      filename: "main.css"//抽离css之后输出的文件名
    })
  ],
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.styl$/,//匹配到styl结尾的文件,加载stylus-loader,
        use: [
          MiniCssExtractPlugin.loader,//抽离成css文件,用link形式链接
          "css-loader",
          "stylus-loader"
        ]
      },
    ]
  }
}
  1. 引入mini-css-extract-plugin插件
  2. 将插件添加到plugins中,设置输出文件名
  3. 设置loader,替换掉原来的style-loader

因为<link><style>引入css的形式只需要一个就可以了。

运行:

npm run dev

查看执行结果,可以看到编译后展示的html里面,是以<link>引入的css文件,

生成了一个名叫main.css的文件,此文件名是webpack配置中指定的。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
<link href="main.css?aab0709b375bbd6d408b" rel="stylesheet"></head>
<body>
  <!-- 模版,此处插入js脚本 -->
  <div>我是毛毛</div>
<script src="bundle.aab0709b.js?aab0709b375bbd6d408b"></script></body>
</html>

6、css自动生成 浏览器前缀

类似于:

这样的浏览器平台特有属性,是不是不想在写css样式的时候操心?

要是插件可以自动生成对应平台的支持属性,是不是很nice?

这里要用到:autoprefixer插件。

autoprefixer需要postcss-loader的支持

安装:

npm install postcss-loader autoprefixer -D

webpack文件添加配置:

  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.styl$/,//匹配到styl结尾的文件,加载stylus-loader,
        use: [
          MiniCssExtractPlugin.loader,//抽离成css文件,用link形式链接
          "css-loader",
          "postcss-loader",
          "stylus-loader"
        ]
      },
    ]
  }

运行npm run dev

发现有报错:


ERROR in ./src/index.styl
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/src/index.js):
Error: No PostCSS Config found in: /Users/maomao/Documents/demo/h5/mm_webpack/src
    at /Users/maomao/Documents/demo/h5/mm_webpack/node_modules/postcss-load-config/src/index.js:91:15
    at processResult (/Users/maomao/Documents/demo/h5/mm_webpack/node_modules/webpack/lib/NormalModule.js:598:19)
    at /Users/maomao/Documents/demo/h5/mm_webpack/node_modules/webpack/lib/NormalModule.js:692:5
    at /Users/maomao/Documents/demo/h5/mm_webpack/node_modules/loader-runner/lib/LoaderRunner.js:399:11
    at /Users/maomao/Documents/demo/h5/mm_webpack/node_modules/loader-runner/lib/LoaderRunner.js:251:18
    at context.callback (/Users/maomao/Documents/demo/h5/mm_webpack/node_modules/loader-runner/lib/LoaderRunner.js:124:13)
    at /Users/maomao/Documents/demo/h5/mm_webpack/node_modules/postcss-loader/src/index.js:208:9
 @ ./src/aaa.js 4:0-23

1 ERROR in child compilations
webpack 5.21.2 compiled with 2 errors in 732 ms
ℹ 「wdm」: Failed to compile.

提示没有PostCSS Config文件。

于是,

创建postcss.config.js文件,并编辑:

module.exports = {
    plugins: [require("autoprefixer")]
}

然后继续运行:npm run dev

这次不报错了,但是我这边发现运行起来的文件并没有添加浏览器平台样式。

网上找原因,发现是需要在package.json中配置浏览器支持。

我现有的package.json浏览器相关配置是这样的:

  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },

修改为:

  "browserslist": [
    "defaults",
    "not ie < 8",
    "last 2 versions",
    "> 1%",
    "iOS 7",
    "last 3 iOS versions"
  ],

再次运行:npm run dev

发现浏览器中针对css3样式添加了平台样式支持:

如:-webkit-transform: rotate(145deg);

body {
    margin: 0;
    background-color: #ffc0cb;
    -webkit-transform: rotate(145deg);
    transform: rotate(145deg);
}

7、压缩优化CSS文件

使用插件:optimize-css-assets-webpack-plugin

安装:

npm install optimize-css-assets-webpack-plugin -D

webpack文件中添加如下配置:

let OptimizeCssPlugin = require("optimize-css-assets-webpack-plugin")//压缩css 插件
module.exports = {
  plugins: [//存放所有插件
    new OptimizeCssPlugin()//css优化插件
  ],
}

运行结果,发现css文件被优化成一行:

body{margin:0;background-color:pink;-webkit-transform:rotate(145deg);transform:rotate(145deg)}

这里有个注意点!

使用:optimize-css-assets-webpack-plugin插件之后,js的原始压缩方案将失效。

需要添加新的js压缩插件:uglifyjs-webpack-plugin

安装:

npm install uglifyjs-webpack-plugin -D

webpack文件中添加如下配置:

let UglifyJsPlugin = require("uglifyjs-webpack-plugin")//压缩js 插件
module.exports = {
  plugins: [//存放所有插件
    new UglifyJsPlugin(),//js优化插件
  ],
}

运行:npm run build

发现js文件也被优化成一行。

本节完。

完整webpack文件配置:

//webpack 是用nodejs写的,是node语法

let path = require('path')//node提供的 相对路径 转 绝对路径 的插件
let HtmlWebpackPlugin = require("html-webpack-plugin")//html webpack 插件
let MiniCssExtractPlugin = require("mini-css-extract-plugin")//抽离css 插件
let OptimizeCssPlugin = require("optimize-css-assets-webpack-plugin")//压缩css 插件
let UglifyJsPlugin = require("uglifyjs-webpack-plugin")//压缩js 插件
module.exports = {
  devServer: {//开发服务器配置
    port: 3000,//端口号
    progress: true,//进度条
    contentBase: "./dist",//返回的资源目录
    compress: true//是否压缩
  },
  mode: "development",//模式,两种模式,产线模式"production"、开发模式"development"。产线模式会把编译文件进行压缩优化,代码变成一行。
  entry: "./src/aaa.js",//入口,相对路径
  output: {
    filename: "bundle.[hash:8].js",//打包后的文件名
    path: path.resolve(__dirname, "dist"),//打包后的路径(文件夹路径),必须是绝对路径,"__dirname"指当前路径
  },

  plugins: [//存放所有插件
    new HtmlWebpackPlugin({
      template: "./src/index.html",//模版文件(源文件)地址
      filename: "index.html",//打包后文件名
      minify: {
        removeAttributeQuotes: true,//删除双引号
        collapseWhitespace: true,//折叠空行(变成一行)
      },
      hash: true,//引用时文件名加上hash戳
    }),
    new MiniCssExtractPlugin({
      filename: "main.css"//抽离css之后输出的文件名
    }),
    new OptimizeCssPlugin(),//css优化插件
    new UglifyJsPlugin(),//js优化插件
  ],
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.css$/,//匹配到css结尾的文件,加载css-loader,
        //css-loader负责解析@import语法,将多个css文件合并成一个
        //style-loader负责把css文件插入到<head>标签中
        //loader的特点:功能单一
        //loader的用法:
        //use:"css-loader"字符串形式只能用一个loader
        //use:[]数组形式可以用多个loader
        //多个loader时,加载顺序是从后往前加载(从右向左执行)
        use: [{
          loader: "style-loader",
          options: {
            // insert: "top",//将当前loader添加到<head>标签内容的最上面

            insert: function (element) {
              var parent = document.querySelector('head');
              var lastInsertedElement = window._lastElementInsertedByStyleLoader;
              if (!lastInsertedElement) {
                parent.insertBefore(element, parent.firstChild);
              } else if (lastInsertedElement.nextSibling) {
                parent.insertBefore(element, lastInsertedElement.nextSibling)
              } else {
                parent.appendChild(element)
              }
            }
          }
        },
          "css-loader",
          "postcss-loader"]
      },
      {
        test: /\.styl$/,//匹配到styl结尾的文件,加载stylus-loader,
        use: [
          MiniCssExtractPlugin.loader,//抽离成css文件,用link形式链接
          "css-loader",
          "postcss-loader",
          "stylus-loader"
        ]
      },
    ]
  }
}