乐趣区

从0搭建自己的webpack开发环境二

上期回顾:从 0 搭建自己的 webpack 开发环境(一)

loader主要是用于把模块原内容按照需求转换成新内容,以便用来加载非 JS 模块!
通过使用不同的 loaderWebpack 可以把不同的文件都转成 JS 文件,比如 CSS、ES6/7、JSX 等。

让我们来看看这些必须要掌握的 loader!

1.loader 的编写

1.1 loader 的使用

  • test:匹配处理文件的扩展名的正则表达式
  • use:loader 名称,就是你要使用模块的名称
  • include/exclude:手动指定必须处理的文件夹或屏蔽不需要处理的文件夹
  • options:为 loaders 提供额外的设置选项

默认 loader 的执行顺序是 从下到上 * 从右向左,当然执行顺序也可以手动定义,接下来我们依次介绍常见的loader,来感受loader 的魅力!

我们基于这个基础配置来继续编写:

const path = require("path");
const dev = require("./webpack.dev");
const prod = require("./webpack.prod");
const merge = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const base = {
  entry:'./src/index.js',
  output: {filename: "[name].js",
    path: path.resolve(__dirname, "../dist")
  },
  plugins: [
    new HtmlWebpackPlugin({
        filename: 'index.html',
        template: path.resolve(__dirname, "../public/template.html"),
        hash: true,
        minify: {removeAttributeQuotes: true}
    }),
    new CleanWebpackPlugin({cleanOnceBeforeBuildPatterns: [path.resolve('xxxx/*'),'**/*'],
    }),
  ]
};
module.exports = env => {if (env.development) {return merge(base, dev);
  } else {return merge(base, prod);
  }
};

2. 处理 CSS 文件

2.1 解析 css 样式

我们在 js 文件中引入 css 样式!

import './index.css';

再次执行打包时,会提示 css 无法解析

ERROR in ./src/index.css 1:4
Module parse failed: Unexpected token (1:4)
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

这个时候需要 安装 loader

npm install style-loader css-loader --save-dev
module: {
  rules: [
    {
       test: /\.css$/,
       use: ["style-loader", "css-loader"]
    }
  ]
}

2.2 抽离样式文件

默认只在打包时进行样式抽离

module.exports = env => {
  let isDev = env.development;
  const base = {/*source...*/}
  if (isDev) {return merge(base, dev);
  } else {return merge(base, prod);
  }
};

安装抽离插件

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

配置抽离插件

{
    test: /\.css$/,
    use: [
        !isDev && MiniCssExtractPlugin.loader,
        isDev && 'style-loader',
        "css-loader"
    ].filter(Boolean)
}
!isDev && new MiniCssExtractPlugin({filename: "css/[name].css"
})

最终文件配置贴一下:

const path = require("path");
const dev = require("./webpack.dev");
const prod = require("./webpack.prod");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = env => {
  let isDev = env.development;
  const base = {
    entry: "./src/index.js",
    output: {filename: "[name].js",
      path: path.resolve(__dirname, "../dist")
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            !isDev && MiniCssExtractPlugin.loader,
            isDev && 'style-loader',
            "css-loader"
          ].filter(Boolean)
        }
      ]
    },
    plugins:[
        !isDev && new MiniCssExtractPlugin({filename: "css/[name].css"
        }),
        new HtmlWebpackPlugin({
          filename: "index.html",
          template: path.resolve(__dirname, "../public/template.html"),
          hash: true,
          minify: {removeAttributeQuotes: true}
        }),
      ].filter(Boolean)
  };
  if (isDev) {return merge(base, dev);
  } else {return merge(base, prod);
  }
};

2.3 css 预处理器

不同的 css 预处理器 要安装不同的 loader 来进行解析

  • sass: sass-loader node-sass
  • less: less-loader less
  • stylus: stylus-loader stylus

使用sass

{
    test:/\.scss$/,
    use:[
        !isDev && MiniCssExtractPlugin.loader,
        isDev && 'style-loader',
        "css-loader",
        "sass-loader"
    ].filter(Boolean)
}

在 css 文件中可能会使用 @import 语法引用 css 文件,被引用的 css 文件中可能还会导入scss

{
    test: /\.css$/,
    use: [
    !isDev && MiniCssExtractPlugin.loader,
    isDev && 'style-loader',
    {
        loader:"css-loader",
        options:{importLoaders:1 // 引入的文件需要调用 sass-loader 来处理}
    },
    "sass-loader"
    ].filter(Boolean)
},

2.4 处理样式前缀

使用 postcss-loader 增加样式前缀

npm install postcss-loader autoprefixer

在处理 css 前先增加前缀

 {
    test: /\.css$/,
    use: [
    !isDev && MiniCssExtractPlugin.loader,
    isDev && 'style-loader',
    {
        loader:"postcss-loader",
        options:{plugins:[require('autoprefixer')]
        }
    },
    "postcss-loader",
    "sass-loader"
    ].filter(Boolean)
},

或者也可以创建 postcss 的配置文件postcss.config.js

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

可以配置浏览器的兼容性范围 .browserslistrc

cover 99.5%

2.5 css 压缩

在生产环境下我们需要压缩 css 文件,配置 minimizer 选项,安装压缩插件

npm i optimize-css-assets-webpack-plugin terser-webpack-plugin --save-dev

webpack.prod.js 文件中配置压缩

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
optimization:{minimizer:[new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
}

2.6 文件指纹

  • Hash:整个项目的 hash 值
  • chunkhash:根据入口产生 hash 值
  • contentHash:根据每个文件的内容产生的 hash 值

我们可以合理的使用 hash 戳,进行文件的缓存

!isDev && new MiniCssExtractPlugin({filename: "css/[name].[contentHash].css"
})

3. 处理文件类型

3.1 处理引用的图片

import logo from './webpack.png';
let img = document.createElement('img');
img.src = logo;
document.body.appendChild(img);

使用file-loader,会将图片进行打包,并将打包后的路径返回

{
    test:/\.jpe?g|png|gif/,
    use:{
        loader:'file-loader',
        options:{name:`img/[name].[ext]`
        }
    }
}

3.2 处理 icon

二进制文件也是使用 file-loader 来打包

{
    test:/woff|ttf|eot|svg|otf/,
    use:{loader:'file-loader'}
}

3.3 转化成 base64

使用 url-loader 将满足条件的图片转化成 base64,不满足条件的 url-loader 会自动调用 file-loader 来进行处理

{
    test:/\.jpe?g|png|gif/,
    use:{
        loader:'url-loader',
        options:{
            limit:100*1024,
            name:`img/[name].[ext]`
        }
    }
}

4. 小结

通过对 loader 的使用,我们了解到 loader 可以把其他类型模块都处理成 JS 模块,以便加载使用。这其实就是 webpack 中非常重要的混淆依赖中的一部分。
下一篇文章我们将一起来探讨如何解析处理 JS 模块,希望大家继续关注和支持!


退出移动版