webpack的loaders和plugins的简单介绍

384 阅读4分钟

webpack loaders和plugins介绍

什么是loaders

对于webpack来说,默认只能打包处理JS文件,或者说是JS模块,但是作为一个模块打包工具,需要打包的模块肯定不仅仅只有JS模块,还有图片,CSS模块等。

但webpack不能打包除JS模块之外的其他模块。

所以需要引入第三方loader告诉它,碰见这些文件要怎么办。

所以,loader就是一个打包方案,仅仅是为了打包。

什么是plugins

loaders用来转换某种特定类型的模块,plugins则是用来在一些合适的时机执行一些特定的任务,比如代码分割、打包优化、压缩等。

扩展webpack的功能的,目的是做任何loaders做不了的事情。

是作用于webpack本身上,可以在webpack运行到某个时刻的时候,做一些事情,在整个编译周期都起作用。

loaders和plugins的区别

  • loader在模块加载时的预处理文件,运行在打包文件之前。
  • plugins处理loader无法处理的事物,在整个编译周期都起作用。

常用的loaders介绍

file-loader

{
  test: /\.(png|jpg|gif)$/,
    use: {
        loader: 'file-loader',
        options: {},
    },
}
  • 实现方式:依靠webpack提供的强大的API,自己本身并没有做多少工作,完全不用担心读写文件的问题,因为这些webpack已经封装好了
  • 在js代码里import/require 一个文件时,会将该文件生成到输出目录,随机生成一个hash值,返回到require函数
let img = require('@/assets/img/default-avatar.png');
console.log(img); // 95dbac1b85f0161c12c34cbbf34d5156.png

url-loader

  {
    test: /\.(png|svg|jpe?g|gif)$/,
      use: {
        loader: 'url-loader',
          options: {
            name: '[name]_[hash].[ext]',
              outputPath: 'img',
                limit: 10240
          }
      }
  },
  • 实现方式:获取 limit 参数,如果文件大小在 limit之内,则返回文件的 base64 编码后内容;如果超过了 limit ,则调用file-loader,调用的时候,会将options内容也传递给file-loader
  • url-loader 默认 limit 是没有限制,如果没有设置,不管多大的图片都会转换为 base64 编码字符串。
    url-loaders2.png
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          {
            loader: 'style-loader', // creates style nodes from JS strings
          },
          {
            loader: 'css-loader', // translates CSS into CommonJS
          },
          {
            loader: 'less-loader', // compiles Less to CSS
          },
        ],
      },
    ],
  },
};

less-loader

  • 将less编译成 css
  • 交给css-loader

css-loader

  • 主要用来解析css中的静态资源,将@import和url()解析为import/require(),解析出的除css以外的静态资源,一般交给url-loader和file-loader去处理
  • 为了不造成冲突,css-loader可以按照一定的规则将类名等转化成具有全局唯一性的名字
  • 将css转化为commonjs

postcss-loader

  • 配合postcss.config.js使用
  • css3新特性加厂商前缀(autoprefixer)
  • 如果在浏览器中没有看到加前缀,是因为浏览器版本较高
  • 可以对css进行各种处理,功能强大,比如自动添加css前缀,也可自定义插件

style-loader

  • 将样式挂在在head里
  • 通过注入<style>标签将CSS添加到DOM

loader的使用

  • loader的执行顺序是从下到上,从右到左
  • 他们的解析过程是链式的,所以在use数组中下面的部分会先执行,所以他们的执行顺序其实是less-loader > css-loader > style-loader
  • 前一个loader的结果是下一个loader的输入,最后一个loader的输出就是我们要的结果。
{
    test: /\.less/,
	use: [
		'style-loader',
		{
			loader: 'css-loader'
		},
		{
			loader: 'postcss-loader',
			options: {
				ident: 'postcss',
				plugins: loader => [
					require('autoprefixer')({
						browsers: ['last 2 versions', 'ios >= 8']
					})
				]
			}
		},
		{
			loader: 'less-loader'
		}
	]
	// use style-loader in development
},

编写一个超简单的loader

loader文件

module.exports = function (source) {
    return source.replace('winnie', 'world')
}

loader使用

resolveLoader: {
        modules: ['node_modules', './loaders']
    },
    module: {
        rules: [{
            test: /\.js/,
            use: [{
                    loader: 'replaceLoader',
                },
            ]
        }]
},

常用的plugins介绍

html-webpack-plugin

  • 会在打包结束后,自动生成一个html文件,并把打包生成的js文件自动引入到这个html中,打包之后运行
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
  new HtmlWebpackPlugin({ // 生成一个html文件,并且将打包文件插入到html中
    filename: 'index.html',
    template: 'index.html',
    title: '小白营',
  }),
]

clean-webpack-plugin

  • 打包之前运行,默认移除webpack的output中的所有文件,然后将输出的文件输出到输出目录中
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
	new CleanWebpackPlugin(), // 打包前清空打包文件
]

DllPlugin

  • 用于打包出一个个单独的动态链接库文件

DllReferencePlugin 插件

  • 用于在主配置文件中去引入 DllPlugin 插件打包好的动态链接库文件
  • DllPlugin和DllReferencePlugin需要配合使用

webpack性能优化

  • 使用DllPlugin提高打包速度:目的-引入的第三方模块只打包一次保存,之后打包不再重复编译

  • 配置webpack.dll.js文件:将第三方模块单独打包,用library将第三方模块的代码通过全局变量的方式暴露出去,然后借助DLLPlugin插件分析暴露出去的代码,生成manifest.json映射文件

  • manifest.json用于描述动态链接库文件中包含哪些模块

const path = require('path');
const webpack = require('webpack');
module.exports = {
    mode:'production',
    entry: {
        vendors:['lodash','react','react-dom',]
    },
    output: {
        path: path.resolve(__dirname, '../dll'),
        filename:'[name].dll.js',
        library:'[name]'
    },
    plugins:[
        new webpack.DllPlugin({
            name: '[name]',
            path: path.resolve(__dirname, '../dll/[name].manifest.json')
        })
    ]
}
  • 引入AddAssetHtmlWebpackPlugin,将打包的dll文件引入html
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
new AddAssetHtmlWebpackPlugin({
	filepath: path.resolve(__dirname,'../dll/vendors.dll.js')
}),
  • 引入DllReferencePlugin,结合生成的dll文件和引入的第三方模块,分析manifest.json,打包时,三方代码直接从生成的dll文件中拿
new webpack.DllReferencePlugin({
	manifest: path.resolve(__dirname,'../dll/vendors.manifest.json')
})
  • manifest.json清楚地描述了与其对应的 dll.js 文件中包含了哪些模块,以及每个模块的路径和 ID manifest.png
  • 一个动态链接库文件中包含了大量模块的代码,这些模块存放在一个数组里,用数组的索引号作为 ID。 并且还通过 vendors 变量把自己暴露在了全局中,也就是可以通过 window.vendors 可以访问到它里面包含的模块 vendors.png