深刻學習webpack(三)

  在前面兩篇博客中,主要講了webpack的使用和webpack的核心概念,他們都是很是重要的,在這篇博客中,講主要討論webpack配置相關問題。css

  參考文章:https://webpack.js.org/configuration/ html

  對於配置文件中不懂的地方均可以在上面的文章中找到最精確的文檔來查看學習。vue

第一部分

  可能你已經注意到了幾乎沒有兩個configuration是相同的,這是由於webpack的配置文件就是一個導出一個對象的js文件。這個對象將會基於自身的屬性被處理。node

  由於這是nodejs中的Commonjs標準,因此咱們能夠這樣作:react

  • 經過require()引入其餘的文件。
  • 經過require()使用npm中的一些功能。
  • 使用js的控制流表達式如 ?: 操做符。
  • 對於常常使用的值使用常量或者變量來表示。

  另外,下面的這些事不推薦的:webpack

  • 當使用webpack CLI時,使用CLI參數。
  • 導出不肯定的值。 
  • 寫了很長的配置(而不是將配置文件分割爲多份不一樣功能的配置文件)。 好比咱們使用vue-cli時就會發現webpack的配置文件有4個之多,這就是爲了防止一個配置文件過大而冗雜。

  下面就是一個最簡單的配置文件:git

var path = require('path');

module.exports = {
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};

  

下面也是一個配置文件,它是包含多對象的:github

var path = require('path');
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');

var baseConfig = {
  target: 'async-node',
  entry: {
    entry: './entry.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'inline',
      filename: 'inline.js',
      minChunks: Infinity
    }),
    new webpack.optimize.AggressiveSplittingPlugin({
        minSize: 5000,
        maxSize: 10000
    }),
  ]
};

let targets = ['web', 'webworker', 'node', 'async-node', 'node-webkit', 'electron-main'].map((target) => {
  let base = webpackMerge(baseConfig, {
    target: target,
    output: {
      path: path.resolve(__dirname, 'dist/' + target),
      filename: '[name].' + target + '.js'
    }
  });
  return base;
});

module.exports = targets;

對於這個配置文件,有下面幾點須要說明:web

  1. 對於配置文件,咱們有不少種組織方式來配置, 最重要的是堅持一致性而且保證你的團隊均可以理解並維護他們。
  2. 對於多個對象,咱們經常使用的就是webpackMerge函數,這個函數能夠將多個對象merge爲一個對象。  
  3. 這裏最後導出的是一個targets數組,其中的每個元素都是合併以後的對象。

第二部分

  不難發現,以前咱們在寫配置文件時每每會用到node的內置模塊---path模塊。經過傳入全局變量__dirname來使用。 這樣能夠防止出現文件的路徑錯誤問題,由於不一樣的操做系統和對於相對路徑/絕對路徑的支持問題。   vue-cli

const path = require('path');

module.exports = {
  // click on the name of the option to get to the detailed documentation
  // click on the items with arrows to show more examples / advanced options

  entry: "./app/entry", // string | object | array
  // Here the application starts executing
  // and webpack starts bundling

  output: {
    // options related to how webpack emits results

    path: path.resolve(__dirname, "dist"), // string
    // the target directory for all output files
    // must be an absolute path (use the Node.js path module)

    filename: "bundle.js", // string
    // the filename template for entry chunks

    publicPath: "/assets/", // string
    // the url to the output directory resolved relative to the HTML page

    library: "MyLibrary", // string,
    // the name of the exported library

    libraryTarget: "umd", // universal module definition
    // the type of the exported library

    /* Advanced output configuration (click to show) */
  },

  module: {
    // configuration regarding modules

    rules: [
      // rules for modules (configure loaders, parser options, etc.)

      {
        test: /\.jsx?$/,
        include: [
          path.resolve(__dirname, "app")
        ],
        exclude: [
          path.resolve(__dirname, "app/demo-files")
        ],
        // these are matching conditions, each accepting a regular expression or string
        // test and include have the same behavior, both must be matched
        // exclude must not be matched (takes preferrence over test and include)
        // Best practices:
        // - Use RegExp only in test and for filename matching
        // - Use arrays of absolute paths in include and exclude
        // - Try to avoid exclude and prefer include

        issuer: { test, include, exclude },
        // conditions for the issuer (the origin of the import)

        enforce: "pre",
        enforce: "post",
        // flags to apply these rules, even if they are overridden (advanced option)

        loader: "babel-loader",
        // the loader which should be applied, it'll be resolved relative to the context
        // -loader suffix is no longer optional in webpack2 for clarity reasons
        // see webpack 1 upgrade guide

        options: {
          presets: ["es2015"]
        },
        // options for the loader
      },

      {
        test: "\.html$",

        use: [
          // apply multiple loaders and options
          "htmllint-loader",
          {
            loader: "html-loader",
            options: {
              /* ... */
            }
          }
        ]
      },

      { oneOf: [ /* rules */ ] },
      // only use one of these nested rules

      { rules: [ /* rules */ ] },
      // use all of these nested rules (combine with conditions to be useful)

      { resource: { and: [ /* conditions */ ] } },
      // matches only if all conditions are matched

      { resource: { or: [ /* conditions */ ] } },
      { resource: [ /* conditions */ ] },
      // matches if any condition is matched (default for arrays)

      { resource: { not: /* condition */ } }
      // matches if the condition is not matched
    ],

    /* Advanced module configuration (click to show) */
  },

  resolve: {
    // options for resolving module requests
    // (does not apply to resolving to loaders)

    modules: [
      "node_modules",
      path.resolve(__dirname, "app")
    ],
    // directories where to look for modules

    extensions: [".js", ".json", ".jsx", ".css"],
    // extensions that are used

    alias: {
      // a list of module name aliases

      "module": "new-module",
      // alias "module" -> "new-module" and "module/path/file" -> "new-module/path/file"

      "only-module$": "new-module",
      // alias "only-module" -> "new-module", but not "module/path/file" -> "new-module/path/file"

      "module": path.resolve(__dirname, "app/third/module.js"),
      // alias "module" -> "./app/third/module.js" and "module/file" results in error
      // modules aliases are imported relative to the current context
    },
    /* alternative alias syntax (click to show) */

    /* Advanced resolve configuration (click to show) */
  },

  performance: {
    hints: "warning", // enum
    maxAssetSize: 200000, // int (in bytes),
    maxEntrypointSize: 400000, // int (in bytes)
    assetFilter: function(assetFilename) { 
      // Function predicate that provides asset filenames
      return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
    }
  },

  devtool: "source-map", // enum
  // enhance debugging by adding meta info for the browser devtools
  // source-map most detailed at the expense of build speed.

  context: __dirname, // string (absolute path!)
  // the home directory for webpack
  // the entry and module.rules.loader option
  //   is resolved relative to this directory

  target: "web", // enum
  // the environment in which the bundle should run
  // changes chunk loading behavior and available modules

  externals: ["react", /^@angular\//],
  // Don't follow/bundle these modules, but request them at runtime from the environment

  stats: "errors-only",
  // lets you precisely control what bundle information gets displayed

  devServer: {
    proxy: { // proxy URLs to backend development server
      '/api': 'http://localhost:3000'
    },
    contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
    compress: true, // enable gzip compression
    historyApiFallback: true, // true for index.html upon 404, object for multiple paths
    hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
    https: false, // true for self-signed, object for cert authority
    noInfo: true, // only errors & warns on hot reload
    // ...
  },

  plugins: [
    // ...
  ],
  // list of additional plugins


  /* Advanced configuration (click to show) */
}
View Code

在上面的配置文件中咱們應該能夠找到大部分遇到的問題了。

 

配置語言

  webpack容許你使用任何語言來寫配置文件。配置文件支持的語言咱們能夠在node-interpret中看到。也就是說,webpack在node-interpret的支持下將會根據你的選擇語言來運行你的配置文件。

  好比,你可使用coffeescript,以下所示:

HtmlWebpackPlugin = require('html-webpack-plugin')
webpack = require('webpack')
path = require('path')
config =
  entry: './path/to/my/entry/file.js'
  output:
    path: path.resolve(__dirname, 'dist')
    filename: 'my-first-webpack.bundle.js'
  module: rules: [ {
    test: /\.(js|jsx)$/
    use: 'babel-loader'
  } ]
  plugins: [
    new (webpack.optimize.UglifyJsPlugin)
    new HtmlWebpackPlugin(template: './src/index.html')
  ]
module.exports = config

  這樣的配置文件也是能夠正常執行的。

 

配置類型

  對於一個配置文件,咱們除了能夠導出一個配置對象,還有不少其餘的方式來知足知足咱們的需求。  

爲使用 --env 導出一個函數

  最終你將會發現這樣一個需求:在你的webpack.config.js中消除developmentproduction builds之間的歧義。你至少有兩個選擇: 

  不是導出一個配置對象,而是導出一個返回的函數,這個函數能夠接受環境參數做爲變量。當你運行webpack時,你能夠指定構建環境的關鍵詞經過 --env, 好比使用 --env.production 或者是 --env.platform=web。 以下所示;

-module.exports = {
+module.exports = function(env) {
+  return {
    plugins: [
      new webpack.optimize.UglifyJsPlugin({
+        compress: env.production // compress only in production build
      })
    ]
+  };
};

  其中的+標識新添加的代碼,其中的-標識不須要、刪除的代碼。 

 

導出一個promise

  webpack將會運行經過配置文件導出的函數而且等待一個promise被返回,當你須要異步的加載配置變量時這是很是方便的。

module.exports = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        entry: './app.js',
        /* ... */
      })
    }, 5000)
  })
}

 

 

 

導出多個配置文件

  不是導出一個配置對象或函數,你能夠導出多個配置文件。 當運行webpack時,全部的配置文件都會被創建, 好比,在建立一個庫時這是很是有用的

module.exports = [{
  output: {
    filename: './dist-amd.js',
    libraryTarget: 'amd'
  },
  entry: './app.js',
}, {
  output: {
    filename: './dist-commonjs.js',
    libraryTarget: 'commonjs'
  },
  entry: './app.js',
}]

 

 

 

//webpack.js.org/guides/production-build/

相關文章
相關標籤/搜索