# WebPack 核心概念

# 什么 Webpack 模块 ?

  • 在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块。
  • 每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
  • 在 web 存在多种支持 JavaScript 模块化的工具,这些工具各有优势和限制。webpack 基于从这些系统获得的经验教训,并将模块的概念应用于项目中的任何文件。

# entry

entry 的基本配置是一个指向文件的地址字符串

const config = {
  entry: {
    main: "./path/to/my/entry/file.js"
  }
};
// 简写
const config = {
  entry: "./path/to/my/entry/file.js"
};
// 数组
const config = {
  entry: ["./path/to/my/entry/file1.js", "./path/to/my/entry/file2.js"]
};
// 对象
const config = {
  entry: {
    app: "./src/app.js",
    vendors: "./src/vendors.js"
  }
};
// 多页面应用程序
const config = {
  entry: {
    pageOne: "./src/pageOne/index.js",
    pageTwo: "./src/pageTwo/index.js",
    pageThree: "./src/pageThree/index.js"
  }
};

对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。

# output

outout 的基本配置是一个对象,至少包含以下两点:

  • filename 输出的文件名
  • path 输出路径
// 基本配置
const config = {
  output: {
    filename: "bundle.js",
    path: "/home/proj/public/assets"
  }
};
// 使用占位符来对应多个入口
const config = {
  entry: {
    app: "./src/app.js",
    search: "./src/search.js"
  },
  output: {
    filename: "[name].js",
    path: __dirname + "/dist"
  }
};
// 上面将会输出 ./dist/app.js ./dist/search.js

// 在进一步,我们使用哈希值来命名打包后的文件
const config = {
  entry: {
    app: "./src/app.js"
  },
  output: {
    filename: "[name].[hash].js",
    path: __dirname + "/dist"
  }
};
// 上面将会输出 ./dist/app.sdf4whq.sj 这里的哈希值却决于真实的文件内容

# mode

提供 mode 配置选项,会告知 webpack 使用相应模式的内置优化,默认支持两种模式分别是developmentproduction

// config中指定
const config = {
  mode: "production"
};
# 也可以从CLI参数中传递
webpack --mode=production

当指定mode的时候会将process.evn.NODE_ENV设置为相同值,反之值设置NODE_ENV则不会自动设置mode

# loader

webpack 自身只能处理 JavaScript,loader 让 webpack 能够处理非 JavaScript 文件
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

在 webpack 中配置 loader 有两个目标:

  • test,正则表达式,用于标识出对应的 loader 进行转换的某个或某些文件
  • use,字符串,表示进行转换时,应该使用那个 loader

    注意在 webpack 中定义 loader 时,要定义在 module.rules 中,而不是 rules

// webpack.config.js
const path = require("path");
const config = {
  ouput: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      { text: "/.txt$/", use: "raw-loader" },
      { test: "/.css$/", use: ["css-loader"] },
      { test: "/.ts$/", use: ["ts-loader"] },
      { test: "/.less$/", use: ["less-loader"] },
      { test: "/.sass$/", use: ["sass-loader"] },
      { test: "/.(mov|mp4)$/", use: ["file-loader"] }
    ]
  }
};

常用 loader 如下:

  • raw-loader val-loader url-loader file-loader
  • json-loader json5-loader cson-loader
  • script-loader babe-loader ts-loader coffee-loader
  • html-loader markdown-loader react-markdown-loader
  • style-loader css-loader less-loader sass-loader postcss-loader
  • eslint-loader mocha-loader jslint-loader
  • vue-loader angular-template-loader

module.rules允许指定多个 loader,这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。

const config = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: "style-loader" },
          {
            loader: "css-loader",
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
};

# plugins

插件是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上! 插件目的在于解决 loader 无法实现的其他事情

webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。

下面是一个 html-webpack-plugin 的使用示例:

const HtmlWebpackPlugin = require("html-webpack-plugin"); //通过 npm 安装
const webpack = require("webpack"); //访问内置的插件
const path = require("path");

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

module.exports = config;