webpack学习笔记

来源:互联网 发布:细说php最新版 编辑:程序博客网 时间:2024/06/10 00:13

是什么

webpack是一个模块打包工具,通过依赖处理模块,并生成那些模块静态资源。
这里写图片描述
观察上图,webpack把所有的资源(js,css和图片等)都当做是模块——webpack中可以引用css,css中可以嵌入图片dataUrl,对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源。


为什么

当今网站正在变成一个web应用:一个页面包含的javascript代码越来越多,结果客户端存在着大量的代码。通过模块系统划分代码到一个个小模块中,是管理大量代码的有效方式。目前有好几种方式用于实现模块和依赖关系定义:

  • <script>标签

    • 简介:这是最基本的代码模块化方式,这种模块输出方式会暴露接口道一个全局对象,即window,需要通过全局对象来访问依赖的模块。
    • 实例:

      <script src="module1.js"></script><script src="module2.js"></script><script src="libraryA.js"></script><script src="module3.js"></script>
    • 缺点
      • 不同模块容易发生 冲突
      • 加载顺序依赖script标签的顺序
      • 在一个大项目中,script标签列表可能变得很长,难以管理
  • CommonJS

    • 简介:CommonJS使用同步的require方法加载依赖模块——模块可以通过给exports对象绑定属性或者给module.exports赋值来定义输出,
    • 实例:

      require("module");require("../file.js");exports.doStuff = function() {};module.exports = someValue;
    • 优点
      • 服务端模块可以重用?
      • 这种方式开发的模块有很多(NPM)
      • 非常简单,很容易使用
    • 缺点
      • 阻塞式的调用不适用于网络(网络请求是异步的)
      • 不能并发请求多个模块
    • 实现
      • node.js
      • browserify
      • modules-webmake
      • wrep
  • AMD

    • 简介:AMD是异步版本的模块CommonJS
    • 实例:

      require(["module", "../file"], function(module, file) { /* ... */ });define("mymodule", ["dep1", "dep2"], function(d1, d2) {    return someExportedValue;});
    • 优点
      • 实现了异步请求方式
      • 并行加载多个模块
    • 缺点
      • 代码读写起来比较吃力
      • 看起来像个变通方案
    • 实现
      • require.js
      • curl
  • ES6

    • 简介:EcmaScript6给Javascript增加了一些语法,形成了另外一种模块系统
    • 实例:

      import "jquery";export function doStuff() {}module "localModule" {}
    • 优点
      • 静态分析很简单?
      • ES标准,不会过时

模块确定了,要在客户端执行,必须从服务器传输到客户端。以下是两种极端的传输方式:

  • 一个请求一个模块
    • 优点:只传输请求的模块
    • 缺点:多个模块需要多次请求,影响性能,应用启动慢
  • 一次请求所有模块
    • 优点:较少的请求消耗
    • 缺点:不需要的模块也会被传输到客户端

上面两种模块加载方式比较极端,我们需要一个能够更加灵活地传输模块的方法。当在编译所有模块的时候,将整个系统划分成多个更小的模块集。各个模块集不会一开始就加载进来,只有在需要的时候才加载,所以初始化的时候并没有包含所有的模块代码。模块集的划分点取决于开发者,例如按功能划分,将该模块依赖的一个个模块当做一个模块集,当访问系统某项功能时,一次请求加载该项功能的模块集。

前面讨论完关于模块的定义与加载,我们发现为什么只提到了Javascript的模块系统,而前段还有许多其他的静态资源需要加载,如:样式表、图片、字体和html模板等。我们能不能像javascript一样使用require来加载指定的静态资源,例如:

require("./style.css");require("./style.less");require("./template.jade");require("./image.png");

一个大点的项目,都会遇到上面的问题——模块划分和静态资源,目前已有的模块打包工具已经不适用了。而webpack作者曾尝试扩展已有的模块打包工具,但也是无法实现所有的构建目标。
webpack的目标:

  • 将所有模块划分成一个个子模块集,在需要的时候才加载
  • 保证较低的加载时间
  • 将每一个静态资源都当做一个模块
  • 能够以模块的方式集成第三方库
  • 能够定制模块打包的每一部分
  • 适用于大型项目

webpack的特性

  • 模块划分
    webpack不仅支持CommonJS——支持同步依赖,而且也支持AMD——支持异步依赖,也是模块划分点,形成一个新的模块集。
  • 加载器
    webpack只能加载本地的Javascript,通过一系列的加载器可以实现不同静态资源的加载。
  • 智能编译
  • 插件系统
    webpack有着丰富的插件系统,大多数内部特性都是基于插件系统。

安装使用

安装

  1. 安装node.js——node.js自带有一个模块管理器npm
  2. 安装webpack
    • 全局安装:npm install webpack -g,如果有将npm全局安装路径加入path,则可以直接在命令行输入webpack命令了
    • 本地安装:npm install webpack --save-d,本地安装后的命令行工具在./node_modules/.bin/webpack.cmd,也可以在npm package.json里的scripts里引用webpack

用法

除了在命令行界面使使用webpack外,也可以直接在代码中使用webpack。

  • 命令行界面
    • webpack --entry entry.js --output bundle.js
    • webpack --config webpack.config.js
    • webpack --config webpack.config.js -d:开发模式
    • webpack --config webpack.config.js -w:观察模式
    • webpack --config webpack.config.js -p:生成模式
  • node.js-api

    • 简单示例

      var webpack = require("webpack");// returns a Compiler instancewebpack({    // configuration}, function(err, stats) {    // ...});
    • 复杂示例

      var webpack = require("webpack");// returns a Compiler instancevar compiler = webpack({    // configuration});compiler.run(function(err, stats) {    // ...});// orcompiler.watch({ // watch options:    aggregateTimeout: 300, // wait so long for more changes    poll: true // use polling instead of native watchers    // pass a number to set the polling interval}, function(err, stats) {    // ...});

常见问题:

  • webpack命令的--confgi选项是做什么的?
    --config用来指定一个配置文件,代替命令行中的选项,从而简化命令。如果直接执行webpack的话,webpack会在当前目录查找名为webpack.config.js的文件。

简单示例

本例展示Hello World!,源代码如下:

  • index.html

    <html>    <head>        <meta charset="utf-8">    </head>    <body>        <script type="text/javascript" src="bundle.js" charset="utf-8"></script>    </body></html>
  • entry.js

    document.write(require("./content.js"));
  • content.js

    module.exports = "Hello World.";

模块打包及运行:

  1. 执行命令webpack ./entry.js bundle.js,该命令会编译entry.js和content.js,并合并生成一个bundle.js。
  2. 在浏览器中打开index.html,显示:Hello World!.

除了在webpack命令选项中指定模块入口文件和模块打包生成文件外,可以创建webpack.config.js来配置,具体配置如下代码所示。配置好后,在命令行中直接输入webpack(默认查找配置文件webpack.config.js)或者webpack --config webpack.config.js,这样效果同上面的命令webpack ./entry.js bundle.js

module.exports = {    entry: "./entry.js",    output: {        path: __dirname,        filename: "bundle.js"    }};

更多关于webpack.config.js的配置见下文。


模块详解

webpack同时支持CommonJS和AMD规范的模块编写方式, Hello World实例已经简单地演示了模块的定义和加载,下面我们开始学习webpack模块相关的api。

模块定义

  • module.exports

    • 简介:CommJS规范的模块定义,module.exports指定的对象作为模块的输出,没有指定的话默认返回一个新对象,即{}。
    • 实例:

      module.exports = function doSomething() {    // Do something};
    • 总结:在加载module.exports格式定义的模块时,模块返回的是module.exports指定的对象
    • 注意点:不可以在异步函数中使用module.exports
  • exports

    • 简介:CommonJS规范的模块定义,exports是被输出的对象,如果已经指定了module.exports,则exports会被忽略
    • 实例:

      exports.someValue = 42;exports.anObject = {    x: 123};exports.aFunction = function doSomething() {    // Do something};
  • export label

    • 简介:Labeld模块定义格式
    • 实例:

      export: var answer = 42;export: function method(value) {  // Do something};
    • 注意点:在异步函数中使用可能得不到想要的效果
  • define

    • 简介:AMD规范的模块定义
    • 语法:
      • define(value: !Function)
        • value 非函数值
      • define([name: String], [dependencies: String[]], factoryMethod: function(...))
        • name String 可选参数,表示模块名
        • dependencies String[] 可选参数,依赖的模块名数组
        • factoryMethod function 必填参数,该函数要求有个返回值,作为模块的输出
    • 示例

      • define with value

        define({    answer: 42});
      • define with factory

        define(["jquery", "my-module"], function($, myModule) {    // Do something with $ and myModule.    // Export a function    return function doSomething() {        // Do something    };});
    • 总结:
      • define没有指定模块名称的时候,默认使用模块所在文件路径和名称作为模块名称,通常推荐使用这个名称就行了,不要再自己指定模块名称。
      • define函数可以指定依赖的模块,需要注意的是这些模块是同步加载的——模块本身和dependencies模块在同一个模块集里,即,webpack构建生成后放到同一个文件里。
    • 注意点:不能在异步函数中使用

模块加载

  • require CommonJs
    • 简介:CommonJS规范的require,同步加载指定的模块。webpack编译器会确保客户端执行到这行代码的时候,依赖的模块已经可用,无需向服务器发送请求——实际上webpack就是把需要加载的模块代码和require合并到同一文件里了,所以无需再发送请求获取模块了。
    • 语法:require(dependency: String)
    • 参数
      • dependency:需要加载的模块名
    • 实例:HellowWorld实例的entry.js中存在这样一行代码document.write(require("./content.js"));,这便是一个commonJS规范的require。这里有两个模块:entry.js和content.js,执行webpack却只生成了一个文件bundle.js。
  • require label
    • 简介:同CommonJS,require label也是同步加载指定模块,只是require语法不通罢了——webpack编译器会处理这种语法
    • 语法:require: "dependency"
    • 实例:
      • webpack自带实例labeled modules
      • 自己写的测试实例labeled-modules
    • 备注:注意require label需要借助插件webpack.dependencies.LabeledModulesPlugin,关于插件的使用,后续会介绍,暂时忽略,本节只是关注require label的写法
  • require AMD

    • 简介:AMD规范的require,异步加载指定的模块——在需要的时候(代码执行到AMD require)才会加载依赖的模块。
    • 语法:require(dependencies: String[], [callback: function(...)])
      • dependencies String[] 需要加载的模块名数组
      • callback function 回调函数,在所有模块加载后执行,dependencies指定的模块实例按参数定义的顺序传递给callback
    • 实例:

      // in file.jsvar a = require("a");var d = require("d);require(["b", "d"], function(b, d) {  var c = require("c");});/* This results in:    * entry chunk        - file.js        - a        - d    * anonymous chunk        - b        - c*/
    • 总结:require AMD会影响webpack的模块打包结果,前面有提到AMD规范的模块依赖便是模块划分点。上例中执行webpack file.js bundle.js生成bundle.js和1.chunk.js,前者包含模块file.js、a.js和d.js,后者包含模块b.js和c.js。关于require AMD模块划分规则,如下所示:
      • dependencies的模块和callback中以CommonJS require的模块在之前都没有加载过,则webpack会将这些模块合并到同一个模块集里,生成一个chunk.js文件
      • dependencies的模块和callback中以CommonJS require的模块在之前有加载过,则加载过的模块会合并的之前的模块集里,本模块集不会包含这个模块,对于没有加载过的模块webpack处理同上
      • callback中以AMD require加载的模块按新的模块集处理
      • 关于如何判断一个模块是否有加载过?webpack编译器自己会处理模块间的依赖关系来分析,一个比较复杂的例子可以参考CommonsJs, AMD and labeled modules mixed
  • require.ensure

    • 简介:与require AMD类似,也是在需要的时候才会加载相应的模块。但不同的是,require.ensure在模块被下载下来后(模块还没被执行)便立即执行回调函数,另外require.ensure可以指定构建后chunk名,如果之前已有require.ensure指定了该名称,webpack会将这些模块统一合并到一个模块集里。
    • 语法:require.ensure(dependencies: String[], callback: function([require]), [chunkName: String])
    • 实例:

      • 简单示例:

        // in file.jsvar a = require("a");require.ensure(["b"], function(require) {    var c = require("c");});require.ensure(["d"], function() {    var e = require("e");}, "my chunk");require.ensure([], function() {    var f = require("f");}, "my chunk");/* This results in:    * entry chunk        - file.js        - a    * anonymous chunk        - b        - c    * "my chunk"        - d        - e        - f*/
      • code-splitted-require.context
      • require.ensure VS require AMD
    • 总结:除了require.ensure可以直接指定模块名外,require.ensure与require AMD一致,都可以进行代码划分,规则也一致。
  • require.include

    • 简介: 确保模块是可用的(已经下载到客户端),但没有执行该模块(还没有得到模块输出),可用于优化模块在模块集的位置
    • 语法:require.include(dependency: String)
    • 实例:

      // in file.jsrequire.include("a");require.ensure(["a", "b"], function(require) {  // Do something});require.ensure(["a", "c"], function(require) {  // Do something});/* This results in:   * entry chunk     - file.js     - a   * anonymous chunk     - b   * anonymous chunk     - cWithout require.include "a" would be in both anonymous chunks.The runtime behavior isn't changed.*/
    • 总结:略

其他API

  • require.resolve: 获取指定模块的id
  • module.id: 当前模块的id
  • require.cache: 模块缓存
  • require.context: 创建模块动态加载上下文,关于上下文的知识,后面章节会介绍
  • module.loaded
  • module.hot: 判断是否开启模块热加载,关于模块热加载的知识,后面章节会介绍
  • global
  • process
  • __dirname
  • __filename
  • __resourcequery
  • webpack_public_path
  • webpack_require
  • webpack_chunk_load
  • webpack_modules
  • require-resolveweak
  • webpack_hash
  • non_webpack_require
  • DEBUG

配置详解

webpack命令提供了一系列的命令选项用于控制模块打包——可通过webpack --help查看这些选项。当需要配置较多的选项时,会使webpack命令变得非常臃肿,如:webpack --entry entry.js --output-path ./build --ouput-file bundle.js。所以webpack提供了一个配置对象来简化项目模块打包,在运行webpack命令的时候,只要指定这个配置对象即可——webpack --config webpack.config.jswebpack.config.js会输出配置对象,例如:

module.exports = {    entry: "./entry.js,    output: {        path: "./build",        filename: "bundle.js"    }};

观察上面的配置对象,可以发现配置对象本身就是一个模块,而不是JSON,我们可以在配置对象中随意的使用Javascript代码。除了在命令行界面中直接使用webpack,也可以在js代码中使用webpack api,例如:

var webpack = require("webpack");webpack({    entry: "./entry.js,    output: {        path: "./build",        filename: "bundle.js"}, callback);

webpack配置对象:

  • context
    webpack处理entry选项时的基础路径(绝对路径),默认值为process.cmd(),即webpack.config.js文件所在路径
  • entry:

    • 简介:webpack模块打包的入口,可以给entry赋字符串类型,数组类型和对象类型的值。
    • 可选值:
      • 字符串:字符串指定的模块在项目程序启动的时候加载
      • 字符串数组:字符串数组指定的所有模块被当做一个模块集,在项目程序启动的时候都会加载,数组最后一个元素作为模块集输出
      • 对象:webpack会打包多个模块集,对象的每个属性名作为模块集的名称,属性值可以是字符串和字符串数组。这个配置可用于实现非单页的程序,程序会有多个启动入口,具体实例可参考multiple entry points。
    • 实例:

      {    entry: {        page1: "./page1",        page2: ["./entry1", "./entry2"]    },    output: {        // Make sure to use [name] or [id] in output.filename        //  when using multiple entry points        filename: "[name].bundle.js",        chunkFilename: "[id].bundle.js"    }}
  • output:option是个对象类型的值,option下的每个属性都可能会影响webpack模块打包结果。
    • output.path:字符串类型的值,指定webpack的输出文件路径——要求是个绝对路径
    • output.filenam: 字符串类型的值,指定模块集生成的文件名——在output.path指定的路径下,另外可以在字符串值中使用下列变量
      • [name]:代表模块集的名称,与entry配置有关,具体可自行测试
      • [hash]:代表编译hash值,与模块集的代码有关,如果模块集的代码有修改,hash值也会变,这个在生成环境里可以解决客户端的缓存问题
      • [chunkhash]:代表模块集名称的hash值,注意chunkhash与hash不能同时使用
    • output.chunckFileName:字符串类型,用于指定非程序入口模块集的文件名称——在output.path指定的路径下,另外可以在字符串值中使用下列变量
      • [id]: 代表模块集的id
      • [name]: 代表模块集的名称,和require.ensure的第三个参数,具体可以自行测试
      • [hash]: 代表编译hash值,与模块集的代码有关,如果模块集的代码有修改,hash值也会变,这个在生成环境里可以解决客户端的缓存问题
      • [chunkhash]: 代表模块集名称的hash值,注意chunkhash与hash不能同时使用
    • output.sourceMapFilename: SourceMaps的文件名称生成规则
    • output.devtoolModuleFilenameTemplate
    • output.devtoolFallbackModuleFilenameTemplate
    • output.devtoolLineToLine
    • output.hotUpdateChunkFilename
    • output.hotUpdateMainFilename
    • output.publicPath
    • output.jsonpFunction
    • output.hotUpdateFunction
    • output.pathinfo
    • output.pathinfo
    • output.library
    • output.libraryTarget
    • output.sourcePrefix
    • output.crossOriginLoading
  • module:用于配置模块加载插件,后面的章节再具体介绍
  • resolve
  • externals
  • target
  • bail
  • profile
  • cache
  • watch
  • watchOptions.aggregateTimeout
  • watchOptions.poll
  • debug
  • devtool
  • node
  • amd
  • loader
  • recordsPath, recordsInputPath, recordsOutputPath
  • plugins: 插件

注:不得不说webpack的强大,提供如此之多的配置选项,由于精力有限,后续再慢慢维护完善各个配置选项的说明。


加载器

加载器简介

加载器在webpack中作为资源(不只是javascript,包含其他静态资源)转换器,它本身是个可以运行在node.js环境中的函数。加载器根据参数对源文件进行处理,返回新的源文件,例如:在webpack中使用加载器处理CoffeeScrip和JSX——CoffeeScript是JavaScript的转译语言,JSX是Javascript的超集,都不能直接运行在浏览器中,但加载器会将他们编译成普通的javascript代码。

加载器的特性:

  • 加载器可以链接使用——多个加载器作用在一个资源上,按编写顺序使用加载器
  • 加载器可以是同步的,也可以是异步的?
  • 加载器运行在nodejs环境里,可以做node.js所能做的一切事情——开发自己的加载器时,可以体会到
  • 加载器可以接受参数,作为加载器的配置来影响加载器对资源的转换
  • 加载器可以通过npm来安装和发布——上面提到了加载器本身就是个运行在node.js环境的函数,所以可以作为node.js包发布在npm上
  • 加载器可以读取webpack的配置
  • 加载器可以结合webpakc的插件使用——插件在后面章节介绍

安装加载器

简介中提到了加载器是发布在npm上,作为一个模块使用——输出一个转换函数。所以我们可以通过npm来安装管理加载器,例如:
npm install xxx-loader --save-dev
或者
npm install xxx-loader --save
作为约定,加载器的命名通常为xxx-loader——xxx是加载器的名字,例如:json-loader。我们既可以使用xxx-loader来引用加载器,也可以直接使用xxx

加载器使用

在webpack中使用加载器有三种方式:
1. 直接在require中引用——不推荐
2. 在webpack.config.js中配置——推荐
3. 通过命令选项配置——不推荐

除了一些特殊情况在require中引用加载器外,我们推荐使用第二种方式来使用加载器——不需要解释,在后面的使用中很容易体会到。

下面简单介绍下这三种方式的用法:

  • require

    • 说明:可以在require语句(或者define,require.ensure等等)中指定加载器,加载器名称与模块名称通过!分割
    • 实例:

      require("./loader!./dir/file.txt");// => uses the file "loader.js" in the current directory to transform//    "file.txt" in the folder "dir".require("jade!./template.jade");// => uses the "jade-loader" (that is installed from npm to "node_modules")//    to transform the file "template.jade"require("!style!css!less!bootstrap/less/bootstrap.less");// => the file "bootstrap.less" in the folder "less" in the "bootstrap"//    module (that is installed from github to "node_modules") is//    transformed by the "less-loader". The result is transformed by the//    "css-loader" and then by the "style-loader".
    • 总结:第一个require使用了当前目录下的加载器./loader.js;第二个require使用了npm安装的加载器jade-loader;第三个加载器使用了加载器的链接特性,首先会使用less-loader处理源文件,处理后的源文件交给css-loader处理,最后交给style-loader——less-loader转换less源文件为普通的css文件,css-loader处理css文件中的url(由于webpack构建的代码会合并统一放在一个路径下,所以要处理下css引用的资源,否则在实际运行时,无法正确找到资源的位置),style-loader会处理css文件,通过js代码将插入到html页面中
  • 配置文件

    • 说明:学习require直接引用加载器后,我们发现很多资源使用的加载器是一样的。webpack提供了配置选项,让我们可以在配置文件中通过正则表达式来匹配资源,指定某一类资源要使用的加载器
    • 实例:

      {    module: {        loaders: [            { test: /\.jade$/, loader: "jade" },            // => "jade" loader is used for ".jade" files            { test: /\.css$/, loader: "style!css" },            // => "style" and "css" loader is used for ".css" files            // Alternative syntax:            { test: /\.css$/, loaders: ["style", "css"] },        ]    }}
  • 命令行选项
    webpack --module-bind jade --module-bind 'css=style!css'

加载器参数

加载器提供了一些参数来控制加载器对资源的转换,添加参数的方式类似于url链接中的查询参数。
- require
require("url-loader?mimetype=image/png!./file.png");
- 配置

`{ test: /\.png$/, loader: "url-loader?mimetype=image/png" }`或者```{    test: /\.png$/,    loader: "url-loader",    query: { mimetype: "image/png" }}```
  • 命令行选项
    webpack --module-bind "png=url-loader?mimetype=image/png"

加载器库

webpack有着丰富的加载器实习,可以参考list-of-loaders来查找你需要的加载器。

简单实例


插件

插件简介

webpack有丰富的插件接口,使得webpack变得更加灵活。webpack内部集成了一些插件,另外在npm上也有发布一些第三方的插件,当然你可以自己根据webpack的接口,开发属于自己的插件。

内建插件

webpack本身提供了一些插件供我们使用,如webpack.optimize.DedupePlugin——查找相等或近似的模块,避免在最终生成的文件中出现重复的模块。下面就以webpack.optimize.DedupePlugin为例展示webpack内部插件的使用:

  • webpack.config.js

    var webpack = require("webpack");var path = require("path");module.exports = {    entry: "./example.js",    output: {        path: path.join(__dirname, "js"),        filename: "output.js"    },    plugins: [        new webpack.optimize.DedupePlugin()    ]}
  • example.js

    var a = require("./a");var b = require("./b");a.x !== b.x;a.y !== b.y;
  • a/index.js

    module.exports = {    x: require("./x"),    y: require("./y"),    z: require("../z")}
  • a/x.js
    module.exports = {"this is": "x"};
  • a/y.js
    module.exports = {"this is": "y", "but in": "a"};
  • b/index.js

    module.exports = {    x: require("./x"),    y: require("./y"),    z: require("../z")}
  • b/x.js
    module.exports = {"this is": "x"};
  • b/y.js
    module.exports = {"this is": "y", "but in": "b"};
  • z.js
    module.exports = {"this is": "z"};
  • js/output.js
  • 总结
    观察上面的示例代码,a和b下都有模块x,且他们的代码是一样的。如果直接在命令行运行webpack example.js output.js,最终的生成文件会有两个模块x。再观察上面的webpack配置文件webpack.config.js,最后增加了plugins: [new webpack.optimize.DedupePlugin()],如果使用这个配置运行webpack构建,可以发现最后的生成文件js/ouput.js里只有个模块x,这个就是插件webpack.optimize.DedupePlugin的作用。

更多内建插件的使用请参考LIST OF PLUGINS

其他插件

除了内建插件外,还有一些webpack插件发布在npm上了,我们可以通过npm命令来安装,例如:
npm install --save-dev extract-text-webpack-plugin——extract-text-webpack-plugin是用于将某些类型的模块,如css,单独提取到文件的插件,具体如何使用该插件可以参考该项目的主页extract-text-webpack-plugin。
如果想要查找更多的webpack插件,可以在npm上利用webpack-plugin关键字来搜索,即webpack-plugin。

自定义插件

Plugins-api


开发工具

webpack-dev-server

认识webpack-dev-server

webpack-dev-server是一个轻量级的node.js服务器,同webpack,webpack-dev-server也可以分析模块的依赖关系进行打包——webpack命令的所有选项对webpack-dev-server命令都有效。但不同的是,webpack-dev-server不会在本地目录下生成目标文件,而是放在内存里,通过访问服务器相应地址获取。另外,webpack-dev-server自带有一个轻量级的runtime,浏览器可以通过Socket.IO与服务器连接,服务器向客户端浏览器送编译状态信息,然后客户端/浏览器根据这些信息做相应的处理,如:刷新,模块热替换等。

简单示例

  • 项目结构
    • app/
      • main.js
    • build/
    • test/
      • index.html
    • webpack.cong.js
  • webpack.config.js
module.exports = {  entry: {    app: ["./app/main.js"]  },  output: {    path: "./build",    publicPath: "/assets/",    filename: "bundle.js"  }};
  • app/main.js
document.write("Hello World!")
  • test/index.html
<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Document</title></head><body>  <script src="assets/bundle.js"></script></body></html>
  • 命令行运行webpack-dev-server --content-base test/
    • 访问项目路径build发现并没有生成相应的构建文件
    • 浏览器访问localhost:8080/,观察运行结果
  • 分析总结
    • webpack-dev-server --content-base test/中的--content-base指定html等静态资源的位置
    • webpack.config.js中的output.publicPath指定webpack模块打包后在服务器的路径

webpack-dev-server命令行接口

所有的webpack命令选项对webpack-dev-server命令都有效,但是没有默认的output参数。除此之外,webpack-dev-server还有一些额外的选项:
- --content-base: 可以是文件、目录或者url,表示静态资源的基础路径
- --quiet: 布尔值,控制是否要在控制台输出所有信息
- --colors: 为控制台输出信息增加一些颜色
- --no-info: 禁止输出一些无聊的信息?
- --host: 主机名或ip地址
- –port: 端口号
- –inline: 布尔值,表示是否要将webpack-dev-server runtime集成到模块打包文件里,可以实现浏览器与服务器的通信
- --hot: 布尔值,表示增加HotModuleReplacementPlugin插件,且将服务器切换到热模式中。注意点:不要再额外添加HotModuleReplacementPlugin
- --https: 布尔值,表示webpack-dev-server是否开启HTTPS协议

webpack-dev-server API

http://webpack.github.io/docs/webpack-dev-server.html#api

最佳实战

在真实的项目开发中,前端需要与后台服务器交互——传输业务数据,这里通常会有一个后台服务器来向前端提供业务数据接口,我们也是在浏览器中访问这个后台服务器来使用功能的。这样的话,我们就需要将webpack生成的静态资源拷贝到我们项目的后台服务器下。如果是在最后发布的话,这样没有什么问题,但在实际开发中,每次调整代码都需要这么做,开发人员在就放弃使用webpack了。
当然,webpack已经为我们解决了这个问题,我们只需要同时运行后台服务器和webpack-dev-server——后台服务器的HTML页面包含指向webpack-dev-server静态资源的script标签,而webpack-dev-server只是充当前端静态资源的服务器。
示例:
- webpack.config.js

module.exports = {  entry: {    app: ["./app/main.js"]  },  output: {    path: "./build",    publicPath: "http://localhost:9090/",    filename: "bundle.js"  }};
  • webpack-dev-server启动命令: webpack-dev-server --config webapck.config.js --host localhost --port 9090 --inline
  • 后台服务器的index.html包含: <script src="http://localhost:9090/bundle.js">
  • 假设后台服务器地址是http://localhost:8080,则在浏览器中访问: http://localhost:8080/index.html

注意点:
- 为了保证总是(为了非入口模块)向webpack-dev-server发送请求来获得静态资源,必须向output.publicPath提供一个完整的URL——如果只是个目录路径的话,非入口模块静态资源的请求会向后台服务器发送,而不是webpack-dev-server
- 为了连接webpacl-dev-server和它的runtime最好在webpack-dev-server命令后加上选项--inline

常见问题

  • webpack-dev-server的运行配置方式?
    • 命令行选项,参考 webpack-dev-server-cli ,此外webpack-dev-server在命令行里也可以使用webpack的配置选项来控制服务器构建
    • nodejs自定义脚本运行,参考api
    • webpack.config.js的 devServer选项,参考 devserver
    • 可参考实例 run-option-mode
  • webpack-dev-server的运行选项content-base与publicPath的区别?
    webpack-dev-server是一个 轻量级 服务器, content-base指定服务静态资源(html等)的路径。webpack-dev-server构建后的代码是放在内存里的,并通过publicPath指定的路径发布,如果没有指定的话在服务器地址的根路径下(如:假设host为127.0.0.1,port为8080,output.filename为bundle,则构建后的代码文件地址是 http://127.0.0.1:8080/bundle.js )
  • hot模式与inline模式?

webpack-dev-middleware

webpack-dev-middleware

koa-webpack-dev

koa-webpack-dev


工具集成

  • grunt
  • gulp
  • bower
  • karma
  • Todo

源码分析

Todo


最佳实战

  • 模块划分
  • 优化
  • Todo

常见问题

  • 不支持的模块(如jQuery插件)格式编译
    • shimming-modules
      • Managing Jquery plugin dependency in webpack
  • echarts整合问题
    • Webpack #1407
    • webpack能加载echarts吗?
    • 请原生支持webpack #1632
    • webpack集成echarts #1625
    • hushicai/echarts-develop

参考文献

社区收藏

  • StackOverflow Webpack Tag
  • segmentfault Webpack Tag

工具对比

  • Browserify vs. Webpack

中文文档

  • Webpack 入门指迷
  • 深入浅出React(二):React开发神器Webpack
  • webpack这个js模块管理器(module bundler)怎么样?
  • webpack前端模块加载工具
  • Webpack 和 Gulp 构建伪命令行项目

最佳实践

  • Getting started with webpack
  • newtriks/generator-react-webpack
  • book-of-modern-frontend-tooling-webpack
  • Tutorial: Setting Up a Single Page React Web App with React-router and Webpack
  • Configure reactjs with webpack and grunt
  • Single Page Modules with Webpack

项目模板

  • ThomasDeutsch/react-webpack
  • jaketrent/html-webpack-template
  • magicdrive/webpack-project-template
  • google webpack project structure

Webpack + React

  • react-webpack-cookbook
  • Creating a workflow with WebPack
  • React Hot Loader
  • 基于ES6,使用React、Webpack、Babel构建模块化JavaScript应用
  • 轻松入门React和Webpack
  • The React.js Way: Getting Started Tutorial
  • 轻松入门React和Webpack
  • webpack前端模块加载工具
  • How-to setup Webpack on an ES6 React Application with SASS?
  • 轻松入门React和Webpack
  • Webpack with LESS and React
  • Building modular javascript applications in ES6 with React, Webpack and Babel
  • 基于ES6,使用React、Webpack、Babel构建模块化JavaScript应用
  • 前端革命,革了再革:WebPack
4 0
原创粉丝点击