webpack学习笔记-2(loader)

2021-03-26  本文已影响0人  miao8862

预处理器:loader

loader本质上是一个函数。在webpack4之前,函数的输入和输出必须为字符串,在webpack4之后,loader开始支持AST(抽象语法树)的传递,通过这种方法减少重复的代码解析。

  output = loader(input) 
  input = 转化后的字符串 | so urce map | ast对象 

webpack会从右到左进行链式打包,将前一个loader转化化的结果作为后一个loader的输入,直到最后一个Loader会将结果送到webpack进行后续处理, 比较典型的是:
output = style-loader(css-loader(sass-loader))

css样式 loader

// webpack.config.js
module.exports = {
  module = {
    rules: [
      {
        test: /\.sass$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
        exclude: /node_modules/,
        include: /src/
      }
    ]
  }
}

常用的loader

css loader

// indexjs
import './style.scss'
$primary-color: pink;
body {
  background-color: $primary-color;
}
{
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: { sourceMap: true }
          },
          {
            loader: 'sass-loader',
            options: { sourceMap: true }
          },
        ]
      },

postcss,为css添加厂商前缀

postcss-loader是为预编译器的一个容器, 它需要额外的一个postcss.config.js进行相关配置
npm i postcss-loader autoprefixer

// webpack.config.js
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader', 'postcss-loader']
}
// postcss.config.js
const autoprefixer = require('autoprefixer')
module.exports = {
  plugins: [
    autoprefixer
  ]
}

babel-loader: 将es6+编译成es5

  1. 将es6形式的字符串内容解析成AST,抽象语法树
  2. 将AST进行语法转换
  3. 生成 ES5代码,并作为字符串返回
    loader在设计的时候就只能接收和返回字符串,不同的loader之间并不需要知道彼此的存在,只要完成好各自的工作就可以了。虽然会产生一些冗余步骤,但这有助于保持loader的独立性和可维护性。
    npm install babel-loader @babel/core @babel/preset-env
  module.exports = {
    module: {
      rules: [
        {
          test: /\.js$/,
          exclued: /node_modules/,
          // 如果要设置配置项,就使用对象
          use: {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true, // 启用缓存机制,在重复打包时未改变过的模块防止二次编译,加快打包速度
            }
          }
        }
      ]
    }
  }

ts-loader

ts的配置,会有一个专门的配置文件,tsconfig.json
npmt i ts-loader typescript

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

html-loader

将html文件转化成字符串并进行格式化,这样我们可以通过.js将.html导入
npm install html-loader

rules: [
  {
    test: /\.html$/,
    use: 'html-loader'
  }
]
<!-- test.html -->
<div>...</div>
import testHtml from './test.html'
document.write(testHtml)

file-loader

打包文件类型的资源,并返回其publicPath
npm i file-loader

const path = require('path');
module.exports = {
  entry: 'app.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: './assets/' // 资源引用路径
  }
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: 'file-loader',
        use: {
          loader: 'file-loader',
          publicPath: './anotherDir/'
        }
      }
    ]
  }
}
import img from './test.jpg'
console.log(img) // 如果output没配置publicPath,则只会输出 hash+文件后缀: hash值.jpg
console.log(img) // output配置了publicPath, 输出:./assets/hash值.jpg
conosle.log(img) // 如果file-loader中配置了publicPath,则输出: ./anotherDir/hash值.jpg

url-loader

url-loader作用和file-loader的作用类似,但多增加了一个文件阈值处理,当大于阈值时,使用file-loader返回publicPath;当小于阈值时,返回文件base64形式编码
npm i url-loader

rules: [
  {
    test: /\.(png|jpg|jpeg|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        limit: 10240,
        name: '[name].[ext]',
        publickPath: './assets/'
      }
    }
  }
]

vue-loader

用于处理vue组件,vue-loader将vue组件的模板、js、css进行拆分,一般配合vue-template-compiler编译vue模板,使用css-loader来处理样式
npm i vue-loader vue-template-compiler

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

自定义一个loader

为所有js文件,启用严格模式,即头部添加:
use strict;

  1. 新建一个文件夹,命名"use-strict-loader"
  2. 初始化npm init -y
  3. 创建index.js,也就是loader的主体
// index.js
module.exports = funtion(content) {
  var useStrictPrefix = '\'use strict\';\n\n'
  return useStrictPrefix + content;
}
  1. 在项目安装这个loader,这时候可以看到项目的node_modules下有一个use-strict-loader目录,它其实就是你刚建的use-strict-loader的一个软链,当你修改use-strict-loader里的文件内容时,引用loader的地方也会随之修改
    npm i <relative-path>/use-strict-loader
module: {
    rules: [
      {
        test: /\.js$/,
        use: 'use-strict-loader'
      }
    ]
  }
  1. 然后打包后,查看bundle.js文件时,可以发现有了‘use strickt’;的字样
/******/ (() => { // webpackBootstrap
/******/    "use strict";
  1. 可以为其添加缓存
// use-strict-loader/index.js
module.exports = function(content) {
  if(this.cacheable){
    this.cacheable();
  }
  var useStrictPrefix = '\'use strict\';\n\n';
  return useStrictPrefix + content;
}
  1. loader接收options配置
// 引用loader的项目/webpack.config.js
module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'use-strict-loader',
          options: {
            sourceMap: true
          }
        }
      }
    ]
  }
// use-strict-loader/index.js
const loaderUtils = require('loader-utils')
module.exports = function(content) {
  if(this.cacheable){
    this.cacheable();
  }
  // 打印获取到的options
  var options = loaderUtils.getOptions(this) || {}
  console.log(options); // { sourceMap: true }
  
  var useStrictPrefix = '\'use strict\';\n\n';
  return useStrictPrefix + content;
}
const loaderUtils = require('loader-utils')
var SourceNode = require('source-map').SourceNode
var SourceMapConsumer = require('source-map').SourceMapConsumer

module.exports = function(content, sourceMap) {
  if(this.cacheable){
    this.cacheable();
  }
  var useStrictPrefix = '\'use strict\';\n\n';
  
  var options = loaderUtils.getOptions(this) || {}
  // console.log('sourceMap:', sourceMap);
  // 存在sourceMap配置项  && sourceMap
  if(options.sourceMap) {
    var currentRequest = loaderUtils.getCurrentRequest(this);
    var node = SourceNode.fromStringWithSourceMap(content, new SourceMapConsumer(sourceMap))
    node.prepend(useStrictPrefix);
    var result = node.toStringWithSourceMap({file: currentRequest});
    // 函数返回时,要使用this.async()获取callback函数,callback函数是为了一次返回多个值
    var callback = this.async();
    // 第一个参数:抛出的错误; 第二个:处理后的源码;第三个:产生的新的source-map
    callback(null, result.code, result.map.toJSON())
  }
  // 如果没有sourceMap配置项,则不进行以上步骤
  return useStrictPrefix + content;
}
上一篇下一篇

猜你喜欢

热点阅读