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
- 简介:CommonJS使用同步的require方法加载依赖模块——模块可以通过给
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有着丰富的插件系统,大多数内部特性都是基于插件系统。
安装使用
安装
- 安装node.js——node.js自带有一个模块管理器npm
- 安装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.";
模块打包及运行:
- 执行命令
webpack ./entry.js bundle.js
,该命令会编译entry.js和content.js,并合并生成一个bundle.js。 - 在浏览器中打开
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.js
,webpack.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语句(或者define,require.ensure等等)中指定加载器,加载器名称与模块名称通过
配置文件
- 说明:学习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
- app/
- 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
- shimming-modules
- 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
- webpack学习笔记
- webpack学习笔记
- webpack学习笔记<使用>
- Webpack 学习笔记
- webpack学习笔记
- webpack 学习笔记
- webpack入门学习笔记
- webpack学习笔记
- webpack学习笔记一
- 【转】webpack学习笔记
- webpack 学习笔记
- Webpack学习笔记
- webpack学习笔记
- webpack学习笔记(一)
- Webpack学习笔记(二)
- webpack学习笔记1
- webpack学习笔记
- webpack学习笔记
- Delphi常用的快捷键
- 字典的创建和使用
- 【leetcode】Kth Smallest Element in a BST
- Senior's Array(5280)
- R语言ggplot2包之坐标轴
- webpack学习笔记
- CGL4.6.1库在win7下的配置
- wamp环境配置
- 变量分裂法(Variable Splitting)
- 4个理由让你必须拥抱互联网+
- 有关date的学习
- Hidden String(5311)
- GPU地址空间的相关概念
- java验证码代码