Webpack Loader种类以及执行顺序

  我们在用webpack构建项目的时候,有两种配置打包文件的方式:

  1. import或者require :a-loader!b-loader!.././static/dog.png(打包某一个文件)
  2. 配置webpack.config.js文件的module.rules(打包某一类的文件)

  针对于以上的第二种方式我贴下我之前一篇博客中的配置 Vue动态注册异步组件(非同一个工程的组件)

var path = require(‘path‘)
var webpack = require(‘webpack‘)

module.exports = {
  entry: process.NODE_ENV === ‘development‘ ? ‘./src/main.js‘ : ‘./src/component/index.js‘,
  output: {
    path: path.resolve(__dirname, ‘./dist‘),
    publicPath: ‘/dist/‘,
    filename: ‘async-component.js‘
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          ‘vue-style-loader‘,
          ‘css-loader‘
        ],
      },
      {
        test: /\.scss$/,
        use: [
          ‘vue-style-loader‘,
          ‘css-loader‘,
          ‘sass-loader‘
        ],
      },
      {
        test: /\.sass$/,
        use: [
          ‘vue-style-loader‘,
          ‘css-loader‘,
          ‘sass-loader?indentedSyntax‘
        ],
      },
      {
        test: /\.vue$/,
        loader: ‘vue-loader‘,
        options: {
          loaders: {
            // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
            // the "scss" and "sass" values for the lang attribute to the right configs here.
            // other preprocessors should work out of the box, no loader config like this necessary.
            ‘scss‘: [
              ‘vue-style-loader‘,
              ‘css-loader‘,
              ‘sass-loader‘
            ],
            ‘sass‘: [
              ‘vue-style-loader‘,
              ‘css-loader‘,
              ‘sass-loader?indentedSyntax‘
            ]
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: ‘babel-loader‘,
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: ‘file-loader‘,
        options: {
          name: ‘[name].[ext]?[hash]‘
        }
      }
    ]
  },
  resolve: {
    alias: {
      ‘vue$‘: ‘vue/dist/vue.esm.js‘
    },
    extensions: [‘*‘, ‘.js‘, ‘.vue‘, ‘.json‘]
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true,
    overlay: true
  },
  performance: {
    hints: false
  },
  devtool: ‘#eval-source-map‘
}

if (process.env.NODE_ENV === ‘production‘) {
  module.exports.devtool = ‘#source-map‘
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      ‘process.env‘: {
        NODE_ENV: ‘"production"‘
      }
    }),
    // new webpack.optimize.UglifyJsPlugin({
    //   sourceMap: true,
    //   compress: {
    //     warnings: false
    //   }
    // }),
    new webpack.LoaderOptionsPlugin({
      minimize: false
    })
  ])
}

  对单文件打包的方式的loader被称为行内(inline)loader;对于rules中的loader,webpack还定义了一个属性 enforce,可取值有 pre(为pre loader)、post(为post loader),如果没有值则为(normal loader)。所以loader在webpack中有4种:normal,inline,pre,post

  贴下官方源码地址 :Loader Type

for (const r of result) {
                        if (r.type === "use") {
                            if (r.enforce === "post" && !noPrePostAutoLoaders) {
                                useLoadersPost.push(r.value);
                            } else if (
                                r.enforce === "pre" &&
                                !noPreAutoLoaders &&
                                !noPrePostAutoLoaders
                            ) {
                                useLoadersPre.push(r.value);
                            } else if (
                                !r.enforce &&
                                !noAutoLoaders &&
                                !noPrePostAutoLoaders
                            ) {
                                useLoaders.push(r.value);
                            }
                        } else if (
                            typeof r.value === "object" &&
                            r.value !== null &&
                            typeof settings[r.type] === "object" &&
                            settings[r.type] !== null
                        ) {
                            settings[r.type] = cachedCleverMerge(settings[r.type], r.value);
                        } else {
                            settings[r.type] = r.value;
                        }
                    }

  所有的loader的执行顺序都有两个阶段:pitching和normal阶段,类似于js中的事件冒泡、捕获阶段(有人嫌官方的词描述的比较晦涩,修改为loader的标记阶段(mark stage)和执行阶段(execution/run stage))。

  对于第二种方式的解释:webpack 官方解释

  1. Pitching阶段: post,inline,normal,pre
  2. Normal阶段:pre,normal,inline,post

  我看有大神的解释如下:(很好理解)

It‘s like the two phases of event bubbling...

a!b!c!resource

pitch a
  pitch b
    pitch c
      read file resource (adds resource to dependencies)
    run c
  run b
run a
When a loader return something in the pitch phase the process continues with the normal phase of the next loader... Example:

pitch a
  pitch b (returns something)
run a

  对应的方式1解析loader的源码

let elements = requestWithoutMatchResource
    .replace(/^-?!+/, "")
    .replace(/!!+/g, "!")
    .split("!");

  对应的方式2解析loader的源码

const result = this.ruleSet.exec({
                        resource: resourcePath,
                        realResource:
                            matchResource !== undefined
                                ? resource.replace(/\?.*/, "")
                                : resourcePath,
                        resourceQuery,
                        issuer: contextInfo.issuer,
                        compiler: contextInfo.compiler
                    });

  那么问题来了,如果我们采用了两种解析loader的方式,他们的执行是什么样的呢?答案是inline loader优先级高于config配置文件中的loader:源码

  webpack使用了neo-async库(用来提供js异步编程的工具库)来解析loader模块,解析inline loader的源码

解析config loader的源码

  webpack官方文档推荐不适用inline loader,最好用在配置文件中使用loader(注意:loader处理的代码中是含有inline loader的)。另外,在特殊情况下我我们可以在inline loader间接改变loader的执行顺序(禁止某些另外3种loader),比如在我们的自己公司某个同事的不是很规范的js库在引入的时候需要禁止掉eslint-loader对其进行处理

  1. 加入 !   前缀禁用配置文件中的普通loader,比如:require("!raw!./script.coffee")
  2. 加入 !!  前缀禁用配置文件中所有的loader,比如:require("!!raw!./script.coffee")
  3. 加入 -!  前缀禁用配置文件中的pre loader和普通loader,但是不包括post loader,比如:require("!!raw!./script.coffee")

  关于loader的禁用,webpack官方的建议是:除非从另一个loader处理生成的,一般不建议主动使用

  1. pre loader 配置:图片压缩
  2. 普通loader 配置:coffee-script转换
  3. inline loader 配置:bundle loader
  4. post loader 配置: 代码覆盖率工具

原文地址:https://www.cnblogs.com/hanshuai/p/11287231.html

时间: 2024-10-08 20:50:39

Webpack Loader种类以及执行顺序的相关文章

揭秘webpack loader

前言 Loader(加载器) 是 webpack 的核心之一.它用于将不同类型的文件转换为 webpack 可识别的模块.本文将尝试深入探索 webpack 中的 loader,揭秘它的工作原理,以及如何开发一个 loader. 一.Loader 工作原理 webpack 只能直接处理 javascript 格式的代码.任何非 js 文件都必须被预先处理转换为 js 代码,才可以参与打包.loader(加载器)就是这样一个代码转换器.它由 webpack 的 loader runner 执行调用

浅析js的执行顺序

javascript是一种描述型的脚本语言,是一种解析语言,由浏览器动态解析,不同种类的浏览器不同版本的浏览器对于js的解析有着微小的差别,不同浏览器的js解析引擎效率也有高低,下面来给大家分析一下js的执行顺序,希望对大家能有所帮助,欢迎大家交流指正. 首先js的执行过程分为两大部分,第一部分,解析过程,也称预编译期.主要工作就是对于js的代码中声明的所有变量和函数进行预处理.需要注意的是,再此进行处理的仅是声明函数,而对于变量的处理仅是声明,并开辟出一块内存空间,不进行复制操作. 第二部分,

虚函数构造和析构函数执行顺序总结

一.定义 虚函数: 在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,可实现函数成员的动态重载. 纯虚函数: 纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做.含有纯虚函数的类被称为抽象类(abstract class) 二.格式 虚函数:virtual <函数返回类型>< 函数名>(<参数表>) {函数体}: 纯虚函数:virtual <函数返回类型&

案例实战之如何写一个webpack loader

通过以下几个实例掌握webpack loader的写法 1.写一个多语言替换的loader 在index.js在页面上插入了一个{{title}}文本,我们需要在打包的时候将其替换成对应的多语言 function component() { let element = document.createElement('div') let str = 'hello webpack loader <h1>{{title}}</h1>' element.innerHTML = str el

iOS程序执行顺序和UIViewController 的生命周期(整理)

说明:此文是自己的总结笔记,主要参考: iOS程序的启动执行顺序 AppDelegate 及 UIViewController 的生命周期 UIView的生命周期 言叶之庭.jpeg 一. iOS程序的启动执行顺序 程序启动顺序图 iOS启动原理图.png 具体执行流程 程序入口进入main函数,设置AppDelegate称为函数的代理 程序完成加载[AppDelegate application:didFinishLaunchingWithOptions:] 创建window窗口 程序被激活[

修饰符-包-内部类-代码块执行顺序

1.访问权限修饰符     从大到小的顺序为:public--protected--default--private     private--只能在同一类中使用;     default--不用写出来,默认不加.可以被同一包中的类使用     protected--可以被不同包的子类使用     public--可以被不同包的其它类使用 2.各种修饰符的修饰对象(可修饰哪些:类/接口/方法/属性)(多个修饰符连用是可以没有顺序的!)     1)访问权限修饰符:public/default--

NAT与ACL执行顺序解析

防火墙数据包处理流程图 ACL与NAT的顺序不是固定的,各厂商数据流先ACL或先NAT不一. 引用<浅析ACL与NAT的执行顺序>-张少芳  一文中的结论如下: H3C 出站:先匹配出站ACL,然后进行地址转换 入站:先进行地址转换,然后匹配入站ACL CISCO 出站:先进行地址转换,然后匹配出站ACL 入站:先匹配入站ACL,然后进行地址转换(即上图所示数据流顺序) 结论 H3C设备和CISCO设备在对ACL与NAT的执行顺序处理上完全相反.由于在实际的网络中可能存在来自不同厂商的设备,因

Java(静态)变量和(静态)代码块的执行顺序

本文讨论Java中(静态)变量.(静态)代码块的执行顺序 首先创建3个类: 1.Foo类,用于打印变量 public class Foo { public Foo(String word) { System.out.println(word); } } 2.Parent类 public class Parent { static Foo FOO = new Foo("Parent's static parameter"); Foo foo = new Foo("Parent'

nginx与Lua执行顺序

Nginx顺序 Nginx 处理每一个用户请求时,都是按照若干个不同阶段(phase)依次处理的,而不是根据配置文件上的顺序. Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是 post-read.server-rewrite.find-config.rewrite.post-rewrite. preaccess.access.post-access.try-files.content.log. post-read: 读取请求内容阶段 Nginx读取并解析完请求头之后就立即