webpack学习记录(4)-常用loader资源解析

228 阅读2分钟

前言

我们前面了解了Webpack的核心功能,知道使用loader来引入其他类型的文件,下面就具体分析下各个loader的使用。

解析ES6

解析ES6时,我们使用的是babel-loader,npm安装如下:

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

用法

module: {
  rules: [
    {
      test: /\.m?js$/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
}

这里我们可以在options中设置babel需要的选项(当然,也可以使用.babelrc文件)。

除此之外,options中也有一些babel-loader自己的选项(详细内容可以查看这里)。

  • cacheDirectory 默认为false,用于缓存loader 的执行结果
  • cacheIdentifier 默认是由@babel/core版本号,babel-loader版本号,.babelrc文件内容(存在的情况下),环境变量BABEL_ENV的值(没有时降级到NODE_ENV)组成的一个字符串。用于判断缓存是否实效。
  • cacheCompression 默认值为true。当设置此值时,会使用Gzip压缩每个Babel transform输出。
  • customize: 默认值为null。导出custom回调函数的模块路径。

最佳实践

  • babel-loader加载慢

一个解决方案是确保转译尽可能少的文件,比如使用loaders配置的exclude选项排除node_modules;一种是使用cacheDirectory来缓存文件。

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          cacheDirectory: true
        }
      }
    }
  ]
}
  • babel会给每个文件注入辅助代码

这里需要引入@babel/plugin-transform-runtime来避免babel自动对每个文件的runtime注入,而是使所有辅助代码从这里引用。

module: {
  rules: [
    {
      test: /\.m?js$/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-transform-runtime']
        }
      }
    }
  ]
}

解析CSS

基础用法

我们使用css-loader加载.css⽂文件,并且转换成commonjs对象。

module: {
  rules: [
    {
      test: /\.css$/i,
      use: 'css-loader'
    }
  ]
}

解析Less和SaSS

现在的项目开发中,一般都使用Less或SaSS,我们需要使用单独的loader对其进行处理。

module: {
  rules: [
    {
      test: /\.less$/i,
      use: ['css-loader', 'less-loader']
    }
  ]
}
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: ['css-loader', 'sass-loader']
      },
    ],
  },
};

自动补齐CSS3前缀

我们使用postcss-loader扩展CSS语法,可以配合autoprefixer插件自动补齐CSS3前缀。

module: {
  rules: [
    {
      test: /\.less$/i,
      use: ['css-loader', 'postcss-loader', 'less-loader']
    }
  ]
}

自动导入默认样式

如果我们需要自动导入一些公用样式或者覆盖其他库提供的样式文件(例如ant-design),可以使用style-resources-loader

module: {
  rules: [
    {
      test: /\.less$/i,
      use: ['css-loader', 'less-loader', {
        loader: 'style-resources-loader',
        options: {
            patterns: [
                './path/from/context/to/scss/variables/*.less',
                './path/from/context/to/scss/mixins/*.less',
            ]
        }
      }]
    }
  ]
}

提取CSS

我们使用mini-css-extract-plugin插件可以将CSS文件抽取为一个文件。

注:mini-css-extract-plugin基于webpack v4,用于替代extract-text-webpack-plugin;且mini-css-extract-plugin不支持代码HRM热更新,所以只在生产模式进行配置

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

module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

插入DOM

我们一般把css-loaderstyle-loader结合起来使用,style-loader可以将CSS插入到DOM<style>标签)中。

注:使用了style-loader,就不使用mini-css-extract-plugin,所以我们一般在开发环境使用style-loader

module: {
  rules: [
    {
      test: /\.css$/i,
      use: ['style-loader', 'css-loader']
    }
  ]
}

注:若为Vue项目,也可以使用vue-style-loader,其为style-loader的一个fork,在style-loader功能上做了一些服务端渲染的支持。

项目相关

解析Vue文件

项目若使用Vue框架,需要通过vue-loader解析.vue文件。

const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      // ... 其它规则
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // 请确保引入这个插件!
    new VueLoaderPlugin()
  ]
}

vue-loader的使用不同于其他loader,需要引入插件VueLoaderPlugin(参考官网)。

解析TypeScript

项目中若使用了TypeScript,需要使用ts-loader来解析.ts文件。

module: {
    rules: [
      { test: /\.(ts|tsx)?$/, loader: 'ts-loader' }
    ]
}

解析图⽚&字体

对图片&字体的解析有两种方案:

  • file-loader

file-loader将文件解析为url,然后将文件发送到输出目录。

module: {
    rules: [
      {
        test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|ico)$/,
        loader: 'file-loader'
      }
    ]
}
  • url-loader

url-loader的工作方式类似于file-loader,但是如果文件小于字节限制(可通过options.limit设置),则可以返回DataURL

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
            },
          },
        ],
      },
    ],
  },
};

构建优化

缓存

在打包构建时,我们在一些性能开销较大的loader之前添加cache-loader,以便将结果缓存到磁盘里。

module.exports = {
  module: {
    rules: [
      {
        test: /\.ext$/,
        use: ['cache-loader', ...loaders],
        include: path.resolve('src'),
      },
    ],
  },
};

worker池

我们可以将thread-loader放置在其他loader之前,那么这些loader会在一个独立的worker池中运行。

每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右。

但是,在worker池中运行的loader是受到限制的。例如:

  • 这些loader不能生成新的文件。
  • 这些loader不能使用自定义的loader API(也就是说,不能通过插件来自定义)。
  • 这些loader无法获取Webpack的配置。
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          "thread-loader",
          // 耗时的 loader (例如 babel-loader)
        ],
      },
    ],
  },
};

参考