Webpack是什么?

webpack is a module bundler.
Webpack是一个模块打包器。

webpack 是一个现代 JavaScript 应用程序的*模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph)*,其中包含应用程序需要的每个模块,然后将所有这些模块打包成少量的 bundle - 通常只有一个,由浏览器加载。

流程图

Webpack的特点:

  • 代码拆分:

Webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块。在优化了依赖树后,每一个异步区块都作为一个文件被打包。

  • Loader:

Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成Javascript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。

  • 智能解析:

Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 js 文件。甚至在加载依赖的时候,允许使用动态表达式 require(“./templates/“ + name + “.jade”)。

  • 插件系统:

Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。

  • 快速运行:

Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译。

Webpack与Gulp的区别?

  • gulp:

gulp强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp执行这些task,从而构建项目的整个前端开发流程。

PS:Automate and enhance your workflow

  • webpack:

webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。

PS:webpack is a module bundle

Webpack的核心概念:

Web是高度可配置的,在开始前需要先理解四个核心概念:入口(entry)、输出(output)、loader、插件(plugins)。

  • entry: 在 webpack 中,我们使用 webpack 配置对象(webpack configuration object)中的 entry 属性来定义入口。看一个最简单的例子:

    module.exports = {
      entry: './path/to/my/entry/file.js'
    };
  • Output:将所有的资源(assets)归拢在一起后,还需要告诉 webpack 在哪里打包应用程序。webpack 的 output 属性描述了如何处理归拢在一起的代码(bundled code)。例子:

    const path = require('path');
    
    module.exports = {
      entry: './path/to/my/entry/file.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
      }
    };
  • Loader: webpack loader 在文件被添加到依赖图中时,其转换为模块。例子:

    const path = require('path');
    
    const config = {
      entry: './path/to/my/entry/file.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
      },
      module: {
        rules: [
          { test: /\.txt$/, use: 'raw-loader' }
        ]
      }
    };
    
    module.exports = config;
  • Plugins:想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 来创建它的一个实例。例子:

    const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
    const webpack = require('webpack'); //to access built-in plugins
    const path = require('path');
    
    const config = {
      entry: './path/to/my/entry/file.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
      },
      module: {
        rules: [
          { test: /\.txt$/, use: 'raw-loader' }
        ]
      },
      plugins: [
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({template: './src/index.html'})
      ]
    };
    
    module.exports = config;

参考资料:核心概念简介

Webpack的安装配置:

前提条件:

请安装和使用 Node.js 最新的长期支持版本(LTS - Long Term Support),使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能以及/或者缺少相关 package 包。

本地安装:

最新版本的webpack是: Github-Webpack-Releases

npm install -g webpack --save-dev

安装完成之后,会在package.json中会添加如下信息:

"devDependencies": {
  "webpack": "^3.4.1"
}

对于大多数项目,建议本地安装。这可以使我们在引入破坏式变更(breaking change)的依赖时,更容易分别升级项目。一般不推荐全局安装 webpack。这会将您项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中,可能会导致构建失败。

Webpack的简单使用:

构建项目:

新建一个index.js文件,在跟该文件中编写一个函数:

// index.js 文件
function func(str) {
  alert(str);
}

编写完成之后可以使用webpack命令了来打包index.js文件,如下所示:

语法: webpack [待打包文件] [打包完成文件名]
例子: webpack index.js index.bundle.js

➜  js webpack index.js index.bundle.js
Hash: 72aeecc257bb3571dac7
Version: webpack 3.4.1
Time: 61ms
          Asset     Size  Chunks             Chunk Names
index.bundle.js  2.51 kB       0  [emitted]  main
   [0] ./index.js 37 bytes {0} [built]

打包输出信息说明:

Name Description
Hash 文件的HASH值
Version webpack的版本
Time 打包所花费的时间
Asset 打包生成的文件
Size 生成文件的大小
Chunks 打包的分块
Chunk Names 打包的块名称

这样就完成了一次简单的打包操作,打包完成之后可以打开index.bundle.js查看一下,Webpack会自动给该文件中添加一些注释还会给一些模块进行编号。

参考资料:Webpack官网简单Demo

Webpack的基本配置:

按照如下目录结构进行构建一个项目:

➜  ~ tree Webpack
Webpack
├── dist
│   ├── css
│   └── js
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── css
│   │   └── style.css
│   ├── index.html
│   └── js
│       └── index.js
└── webpack.config.js

7 directories, 6 files

webpack.config.js

编写webpack.config.js文件:

const webpack = require('webpack');
module.exports = {
  entry:'./src/js/index.js',
  output:{
    path:'/Users/Yang/Documents/Webstorm-Work/Webpack/dist/js', // 设置输出目录
    filename:'[name].bundle.js'  // 输出文件名
  },module:{
    loaders:[
      test:/\.css$/,//支持正则
      loader:'style-loader!css-loader'
    ]
  },resolve:{
   //添加在此的后缀所对应的文件可以省略后缀
   extensions: ['', '.js', '.json', '.css', '.scss']
 },plugins:[
      new webpack.BannerPlugin('This file is created by ly'); // 插件设置
 ]
}

Webpack的Loader使用:

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或”加载”模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

简单示例:

可以使用 loader 告诉 webpack 加载 CSS 文件,或者将 TypeScript 转为 JavaScript。为此,首先安装相对应的 loader:

npm install --save-dev css-loader  # CSS loader
npm install --save-dev ts-loader   # TypeScript loader

然后指示 webpack 对每个 .css 使用 css-loader,以及对所有 .ts 文件使用 ts-loader

webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};

使用 Loader:

在应用程序中,有三种使用 loader 的方式:

  • 配置(推荐):在 webpack.config.js 文件中指定 loader。
  • 内联:在每个 import 语句中显式指定 loader。
  • CLI:在 shell 命令中指定它们。

配置[Configuration]:

module.rules 允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        { loader: 'style-loader' },
        {
          loader: 'css-loader',
          options: {
            modules: true
          }
        }
      ]
    }
  ]
}

内联:

可以在 import 语句或任何等效于 “import” 的方式中指定 loader。使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。

import Styles from 'style-loader!css-loader?modules!./styles.css';

通过前置所有规则及使用 !,可以对应覆盖到配置中的任意 loader。

选项可以传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}

尽可能使用 module.rules,因为这样可以减少源码中的代码量,并且可以在出错时,更快地调试和定位 loader 中的问题。

CLI:

你也可以通过 CLI 使用 loader:

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

这会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loadercss-loader

Loader 特性:

  • loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照先后顺序进行编译。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何可能的操作。
  • loader 接收查询参数。用于对 loader 传递配置。
  • loader 也能够使用 options 对象进行配置。
  • 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。

loader 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译和其他更多

解析 Loader:

loader 遵循标准的模块解析。多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析。

loader 模块需要导出为一个函数,并且使用 Node.js 兼容的 JavaScript 编写。通常使用 npm 进行管理,但是也可以将自定义 loader 作为应用程序中的文件。按照约定,loader 通常被命名为 xxx-loader(例如 json-loader)。有关详细信息,请查看如何编写 loader?

参考资料:Webpack-Loader详解

Webpack的CLI使用:

Output:

通过以下这些配置,你可以调整构建流程的某些输出参数。

常用参数说明:

参数 说明 输入类型 默认值
–output-chunk-filename 输出的附带 chunk 的文件名 string 含有[id] 的文件名,而不是 [name] 或者 [id] 作为前缀
–output-filename 打包文件的文件名 string [name].js
–output-jsonp-function 加载 Chunk 时使用的 JSONP 函数名 string webpackJsonp
–output-library 以库的形式导出入口文件 string
–output-library-target 以库的形式导出入口文件时,输出的类型 string var
–output-path 输出的路径(在公共路径的基础上) string 当前目录
–output-pathinfo 加入一些依赖信息的注解 boolean false
–output-public-path 输出文件时使用的公共路径 string /
–output-source-map-filename 生成的 SourceMap 的文件名 string [name].map or [outputFilename].map

Debug:

以下这些配置可以帮助你在 Webpack 编译过程中更好地 debug。

常用参数说明:

参数 说明 输入类型 默认值
–debug 把 loader 设置为 debug 模式 boolean false
–devtool 为打包好的资源定义source map 的类 string -
–progress 打印出编译进度的百分比值 boolean false

Model:

这些配置可以用于绑定 Webpack 允许的模块

常用参数说明:

参数 说明 使用方法
–module-bind 为 loader 绑定一个扩展 –module-bind js=babel-loader
–module-bind-post 为 post loader 绑定一个扩展
–module-bind-pre 为 pre loader 绑定一个扩展

Watch:

这些配置可以用于观察依赖文件的变化,一旦有变化,则可以重新执行构建流程。

常用参数说明:

参数 说明
–watch, -w 观察文件系统的变化
–save, -s 在保存的时候重新编译,无论文件是否变化
–watch-aggregate-timeout 指定一个毫秒数,在这个时间内,文件若发送了多次变化,会被合并
–watch-poll 轮询观察文件变化的时间间隔(同时会打开轮询机制
–watch-stdin, –stdin 当 stdin 关闭时,退出进程

Optimize:

在生产环境的构建时,这些配置可以用于调整的一些性能相关的配置。

常用参数说明:

参数 解释说明 使用的插件
–optimize-max-chunks 限制 chunk 的数量 LimitChunkCountPlugin
–optimize-min-chunk-size 限制 chunk 的最小体积 MinChunkSizePlugin
–optimize-minimize 压缩混淆 javascript,并且把 loader 设置为 minimizing UglifyJsPlugin & LoaderOptionsPlugin

Resolve:

这些配置可以用于设置 webpack resolver 时使用的别名(alias)和扩展名(extension)。

常用参数说明:

参数 说明 示例
–resolve-alias 指定模块的别名 –resolve-alias jquery-plugin=jquery.plugin
–resolve-extensions 指定需要被处理的文件的扩展名 –resolve-extensions .es6 .js .ts
–resolve-loader-alias Minimize javascript and switches loaders to minimizing

Display:

以下选项用于配置 Webpack 在控制台输出的统计数据,以及这些数据的样式。

常用参数说明:

参数 说明 类型
–color, –colors 开启/关闭控制台的颜色 [默认值: (supports-color)] boolean
–display-cached 在输出中显示缓存的模块 boolean
–display-cached-assets 在输出中显示缓存的 assets boolean
–display-chunks 在输出中显示 chunks boolean
–display-depth 显示从入口起点到每个模块的距离 boolean
–display-entrypoints 在输出中显示入口文件 boolean
–display-error-details 显示详细的错误信息 boolean
–display-exclude 在输出中显示被排除的文件 boolean
–display-max-modules 设置输出中可见模块的最大数量 number
–display-modules 在输出中显示所有模块,包括被排除的模块 boolean
–display-optimization-bailout 作用域提升回退触发器(Scope hoisting fallback trigger)(从 webpack 3.0.0 开始) boolean
–display-origins 在输出中显示最初的 chunk boolean
–display-provided-exports 显示有关从模块导出的信息 boolean
–display-reasons 显示模块包含在输出中的原因 boolean
–display-used-exports 显示模块中被使用的接口(Tree Shaking) boolean
–hide-modules 隐藏关于模块的信息 boolean
–sort-assets-by 对 assets 列表以某种属性排序 string
–sort-chunks-by 对 chunks 列表以某种属性排序 string
–sort-modules-by 对模块列表以某种属性排序 string
–verbose 显示更多信息 boolean
–display 选择显示预设(verbose - 繁琐, detailed - 细节, normal - 正常, minimal - 最小, errors-only - 仅错误, none - 无; 从 webpack 3.0.0 开始) string

Other:

参数 说明 用法
–bail 一旦发生错误,立即终止
–cache 开启缓存 [watch 时会默认打开] –cache=false
–define 定义 bundle 中的任意自由变量,查看 shimming –define process.env.NODE_ENV=’development’
–hot 开启模块热替换 [使用 HotModuleReplacementPlugin] -hot=true
–labeled-modules Enables 开启模块标签 [使用 LabeledModulesPlugin]
-plugin 加载某个插件
–prefetch 预加载某个文件 –prefetch=./files.js
–provide 在所有模块中将这些模块提供为自由变量,查看 shimming –provide jQuery=jquery
–records-input-path 记录文件的路径(读取)
–records-output-path 记录文件的路径(写入)
–records-path 记录文件的路径
–target 目标的执行环境 –target=’node’

参考资料:Webpack-CLI使用

参考资料: