Webpack Loader種類以及執行順序

  咱們在用webpack構建項目的時候,有兩種配置打包文件的方式:css

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

  針對於以上的第二種方式我貼下我以前一篇博客中的配置 Vue動態註冊異步組件(非同一個工程的組件)html

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,postvue

  貼下官方源碼地址 :Loader Typenode

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

  對於第二種方式的解釋:webpack 官方解釋git

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

  我看有大神的解釋以下:(很好理解)github

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的源碼web

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:源碼json

  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 配置: 代碼覆蓋率工具
相關文章
相關標籤/搜索