美文网首页
webpack学习笔记-2(loader)

webpack学习笔记-2(loader)

作者: miao8862 | 来源:发表于2021-03-26 01:02 被阅读0次

    预处理器: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))

    • sass-loader将sass转化成css语法
    • css-loader处理加载@import和url加载的字符串,也是处理在.js文件中引入.css文件的解析(import './index.css')
    • style-loader将这些字符串写入style样式

    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

    • sass: node-sass编译sass,sass-loader起到在webpack应用的黏合作用。
      npm install node-sass sass-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的项目中,配置loader时,添加对应的配置项
    // 引用loader的项目/webpack.config.js
    module: {
        rules: [
          {
            test: /\.js$/,
            use: {
              loader: 'use-strict-loader',
              options: {
                sourceMap: true
              }
            }
          }
        ]
      }
    
    • 在use-strict-loader项目中,安装loader-utils来获取options
      npm i loader-utils
    // 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;
    }
    
    • 运行引用的项目时,就会看到控制台打印出的options: { sourceMap: true }
      npm run dev

    • source-map可以便于实际开发者在浏览器控制台中查看源码。使用source-map库,对自定义的loader进行source-map处理:(这一步有异常,未实现)

    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;
    }
    

    相关文章

      网友评论

          本文标题:webpack学习笔记-2(loader)

          本文链接:https://www.haomeiwen.com/subject/trafhltx.html