Webpack 学习资源整理 供随时查看

来源:互联网 发布:ip网络摄像头监控软件 编辑:程序博客网 时间:2024/04/29 22:22

安装

首先要安装 Node.js, Node.js 自带了软件包管理器 npm,Webpack 需要 Node.js v0.6 以上支持,建议使用最新版 Node.js。

用 npm 安装 Webpack:

$ npm install webpack -g

此时 Webpack 已经安装到了全局环境下,可以通过命令行 webpack -h 试试。

通常我们会将 Webpack 安装到项目的依赖中,这样就可以使用项目本地版本的 Webpack。

# 进入项目目录# 确定已经有 package.json,没有就通过 npm init 创建# 安装 webpack 依赖$ npm install webpack --save-dev

Webpack 目前有两个主版本,一个是在 master 主干的稳定版,一个是在 webpack-2 分支的测试版,测试版拥有一些实验性功能并且和稳定版不兼容,在正式项目中应该使用稳定版。

# 查看 webpack 版本信息$ npm info webpack# 安装指定版本的 webpack$ npm install webpack@1.12.x --save-dev

如果需要使用 Webpack 开发工具,要单独安装:

$ npm install webpack-dev-server --save-dev

使用

首先创建一个静态页面 index.html 和一个 JS 入口文件 entry.js:

<!-- index.html --><html><head>  <meta charset="utf-8"></head><body>  <script src="bundle.js"></script></body></html>
// entry.jsdocument.write('It works.')

然后编译 entry.js 并打包到 bundle.js:

$ webpack entry.js bundle.js

打包过程会显示日志:

Hash: e964f90ec65eb2c29bb9Version: webpack 1.12.2Time: 54ms    Asset     Size  Chunks             Chunk Namesbundle.js  1.42 kB       0  [emitted]  main   [0] ./entry.js 27 bytes {0} [built]

用浏览器打开 index.html 将会看到 It works. 。

接下来添加一个模块 module.js 并修改入口 entry.js

// module.jsmodule.exports = 'It works from module.js.'
// entry.jsdocument.write('It works.')document.write(require('./module.js')) // 添加模块

重新打包 webpack entry.js bundle.js 后刷新页面看到变化 It works.It works from module.js.

Hash: 279c7601d5d08396e751Version: webpack 1.12.2Time: 63ms    Asset     Size  Chunks             Chunk Namesbundle.js  1.57 kB       0  [emitted]  main   [0] ./entry.js 66 bytes {0} [built]   [1] ./module.js 43 bytes {0} [built]

Webpack 会分析入口文件,解析包含依赖关系的各个文件。这些文件(模块)都打包到 bundle.js 。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块。在页面启动时,会先执行 entry.js 中的代码,其它模块会在运行 require 的时候再执行。


Loader

Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。

Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件,比如 CoffeeScript、 JSX、 LESS 或图片。

先来看看 loader 有哪些特性?

  • Loader 可以通过管道方式链式调用,每个 loader 可以把资源转换成任意格式并传递给下一个 loader ,但是最后一个 loader 必须返回 JavaScript。
  • Loader 可以同步或异步执行。
  • Loader 运行在 node.js 环境中,所以可以做任何可能的事情。
  • Loader 可以接受参数,以此来传递配置项给 loader。
  • Loader 可以通过文件扩展名(或正则表达式)绑定给不同类型的文件。
  • Loader 可以通过 npm 发布和安装。
  • 除了通过 package.json 的 main 指定,通常的模块也可以导出一个 loader 来使用。
  • Loader 可以访问配置。
  • 插件可以让 loader 拥有更多特性。
  • Loader 可以分发出附加的任意文件。

Loader 本身也是运行在 node.js 环境中的 JavaScript 模块,它通常会返回一个函数。大多数情况下,我们通过 npm 来管理 loader,但是你也可以在项目中自己写 loader 模块。

按照惯例,而非必须,loader 一般以 xxx-loader 的方式命名,xxx 代表了这个 loader 要做的转换功能,比如 json-loader

在引用 loader 的时候可以使用全名 json-loader,或者使用短名 json。这个命名规则和搜索优先级顺序在 webpack 的 resolveLoader.moduleTemplates api 中定义。

Default: ["*-webpack-loader", "*-web-loader", "*-loader", "*"]

Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

接上一节的例子,我们要在页面中引入一个 CSS 文件 style.css,首页将 style.css 也看成是一个模块,然后用 css-loader 来读取它,再用 style-loader 把它插入到页面中。

/* style.css */body { background: yellow; }

修改 entry.js:

require("!style!css!./style.css") // 载入 style.cssdocument.write('It works.')document.write(require('./module.js'))

安装 loader:

npm install css-loader style-loader

重新编译打包,刷新页面,就可以看到黄色的页面背景了。

如果每次 require CSS 文件的时候都要写 loader 前缀,是一件很繁琐的事情。我们可以根据模块类型(扩展名)来自动绑定需要的 loader。

将 entry.js 中的 require("!style!css!./style.css") 修改为 require("./style.css") ,然后执行:

$ webpack entry.js bundle.js --module-bind 'css=style!css'# 有些环境下可能需要使用双引号$ webpack entry.js bundle.js --module-bind "css=style!css"

显然,这两种使用 loader 的方式,效果是一样的。


配置文件

Webpack 在执行的时候,除了在命令行传入参数,还可以通过指定的配置文件来执行。默认情况下,会搜索当前目录的 webpack.config.js 文件,这个文件是一个 node.js 模块,返回一个 json 格式的配置信息对象,或者通过 --config 选项来指定配置文件。

继续我们的案例,在根目录创建 package.json 来添加 webpack 需要的依赖:

{  "name": "webpack-example",  "version": "1.0.0",  "description": "A simple webpack example.",  "main": "bundle.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "keywords": [    "webpack"  ],  "author": "zhaoda",  "license": "MIT",  "devDependencies": {    "css-loader": "^0.21.0",    "style-loader": "^0.13.0",    "webpack": "^1.12.2"  }}
# 如果没有写入权限,请尝试如下代码更改权限chflags -R nouchg .sudo chmod  775 package.json

别忘了运行 npm install

然后创建一个配置文件 webpack.config.js

var webpack = require('webpack')module.exports = {  entry: './entry.js',  output: {    path: __dirname,    filename: 'bundle.js'  },  module: {    loaders: [      {test: /\.css$/, loader: 'style!css'}    ]  }}

同时简化 entry.js 中的 style.css 加载方式:

require('./style.css')

最后运行 webpack,可以看到 webpack 通过配置文件执行的结果和上一章节通过命令行 webpack entry.js bundle.js --module-bind 'css=style!css' 执行的结果是一样的。


插件

插件可以完成更多 loader 不能完成的功能。

插件的使用一般是在 webpack 的配置信息 plugins 选项中指定。

Webpack 本身内置了一些常用的插件,还可以通过 npm 安装第三方插件。

接下来,我们利用一个最简单的 BannerPlugin 内置插件来实践插件的配置和运行,这个插件的作用是给输出的文件头部添加注释信息。

修改 webpack.config.js,添加 plugins

var webpack = require('webpack')module.exports = {  entry: './entry.js',  output: {    path: __dirname,    filename: 'bundle.js'  },  module: {    loaders: [      {test: /\.css$/, loader: 'style!css'}    ]  },  plugins: [    new webpack.BannerPlugin('This file is created by zhaoda')  ]}

然后运行 webpack,打开 bundle.js,可以看到文件头部出现了我们指定的注释信息:

/*! This file is created by zhaoda *//******/ (function(modules) { // webpackBootstrap/******/  // The module cache/******/  var installedModules = {};// 后面代码省略

开发环境

当项目逐渐变大,webpack 的编译时间会变长,可以通过参数让编译的输出内容带有进度和颜色。

$ webpack --progress --colors

如果不想每次修改模块后都重新编译,那么可以启动监听模式。开启监听模式后,没有变化的模块会在编译后缓存到内存中,而不会每次都被重新编译,所以监听模式的整体速度是很快的。

$ webpack --progress --colors --watch

当然,使用 webpack-dev-server 开发服务是一个更好的选择。它将在 localhost:8080 启动一个 express 静态资源 web 服务器,并且会以监听模式自动运行 webpack,在浏览器打开 http://localhost:8080/ 或 http://localhost:8080/webpack-dev-server/ 可以浏览项目中的页面和编译后的资源输出,并且通过一个 socket.io 服务实时监听它们的变化并自动刷新页面。

# 安装$ npm install webpack-dev-server -g# 运行$ webpack-dev-server --progress --colors

故障处理

Webpack 的配置比较复杂,很容出现错误,下面是一些通常的故障处理手段。

一般情况下,webpack 如果出问题,会打印一些简单的错误信息,比如模块没有找到。我们还可以通过参数 --display-error-details 来打印错误详情。

$ webpack --display-error-detailsHash: a40fbc6d852c51fceadbVersion: webpack 1.12.2Time: 586ms    Asset     Size  Chunks             Chunk Namesbundle.js  12.1 kB       0  [emitted]  main   [0] ./entry.js 153 bytes {0} [built] [1 error]   [5] ./module.js 43 bytes {0} [built]    + 4 hidden modulesERROR in ./entry.jsModule not found: Error: Cannot resolve 'file' or 'directory' ./badpathmodule in /Users/zhaoda/data/projects/webpack-handbook/examplesresolve file  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.webpack.js doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.js doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.web.js doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.json doesn't existresolve directory  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule doesn't exist (directory default file)  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule/package.json doesn't exist (directory description file)[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule][/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.webpack.js][/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.js][/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.web.js][/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.json] @ ./entry.js 3:0-26

Webpack 的配置提供了 resolve 和 resolveLoader 参数来设置模块解析的处理细节,resolve 用来配置应用层的模块(要被打包的模块)解析,resolveLoader 用来配置 loader 模块的解析。

当引入通过 npm 安装的 node.js 模块时,可能出现找不到依赖的错误。Node.js 模块的依赖解析算法很简单,是通过查看模块的每一层父目录中的 node_modules 文件夹来查询依赖的。当出现 Node.js 模块依赖查找失败的时候,可以尝试设置 resolve.fallback 和 resolveLoader.fallback 来解决问题。

module.exports = {  resolve: { fallback: path.join(__dirname, "node_modules") },  resolveLoader: { fallback: path.join(__dirname, "node_modules") }};

Webpack 中涉及路径配置最好使用绝对路径,建议通过 path.resolve(__dirname, "app/folder") 或 path.join(__dirname, "app", "folder") 的方式来配置,以兼容 Windows 环境。


CommonJS 规范

CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。

这个项目最开始是由 Mozilla 的工程师 Kevin Dangoor 在2009年1月创建的,当时的名字是 ServerJS。

我在这里描述的并不是一个技术问题,而是一件重大的事情,让大家走到一起来做决定,迈出第一步,来建立一个更大更酷的东西。 —— Kevin Dangoor's What Server Side JavaScript needs

2009年8月,这个项目改名为 CommonJS,以显示其 API 的更广泛实用性。CommonJS 是一套规范,它的创建和核准是开放的。这个规范已经有很多版本和具体实现。CommonJS 并不是属于 ECMAScript TC39 小组的工作,但 TC39 中的一些成员参与 CommonJS 的制定。2013年5月,Node.js 的包管理器 NPM 的作者 Isaac Z. Schlueter 说 CommonJS 已经过时,Node.js 的内核开发者已经废弃了该规范。

CommonJS 规范是为了解决 JavaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行。该规范的主要内容是,模块必须通过 module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。

一个直观的例子:

// moduleA.jsmodule.exports = function( value ){    return value * 2;}
// moduleB.jsvar multiplyBy2 = require('./moduleA');var result = multiplyBy2(4);

CommonJS 是同步加载模块,但其实也有浏览器端的实现,其原理是现将所有模块都定义好并通过 id 索引,这样就可以方便的在浏览器环境中解析了,可以参考 require1k 和 tiny-browser-require 的源码来理解其解析(resolve)的过程。

更多关于 CommonJS 规范的内容请查看 http://wiki.commonjs.org/wiki/CommonJS。


AMD 规范

AMD(异步模块定义)是为浏览器环境设计的,因为 CommonJS 模块系统是同步加载的,当前浏览器环境还没有准备好同步加载模块的条件。

AMD 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。

模块通过 define 函数定义在闭包中,格式如下:

define(id?: String, dependencies?: String[], factory: Function|Object);

id 是模块的名字,它是可选的参数。

dependencies 指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 factory 中。如果没有指定 dependencies,那么它的默认值是 ["require", "exports", "module"]

define(function(require, exports, module) {})

factory 是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。

一些用例:

定义一个名为 myModule 的模块,它依赖 jQuery 模块:

define('myModule', ['jquery'], function($) {    // $ 是 jquery 模块的输出    $('body').text('hello world');});// 使用define(['myModule'], function(myModule) {});

注意:在 webpack 中,模块名只有局部作用域,在 Require.js 中模块名是全局作用域,可以在全局引用。

定义一个没有 id 值的匿名模块,通常作为应用的启动函数:

define(['jquery'], function($) {    $('body').text('hello world');});

依赖多个模块的定义:

define(['jquery', './math.js'], function($, math) {    // $ 和 math 一次传入 factory    $('body').text('hello world');});

模块输出:

define(['jquery'], function($) {    var HelloWorldize = function(selector){        $(selector).text('hello world');    };    // HelloWorldize 是该模块输出的对外接口    return HelloWorldize;});

在模块定义内部引用依赖:

define(function(require) {    var $ = require('jquery');    $('body').text('hello world');});


模块规范

  • CommonJS 规范
  • Asynchronous Module Definition
  • Common Module Definition
  • CMD 模块定义规范
  • Universal Module Definition
  • ECMAScript 6 Module
  • 什么是 AMD、 CommonJS、 UMD
  • 关于 CommonJS AMD CMD UMD
  • 为什么我推荐 requirejs 而不是 seajs
  • AMD 和 CMD 的区别有哪些
  • 前端模块化开发的价值
  • What Server Side JavaScript needs

模块系统

  • RequireJS
  • curl
  • Sea.js
  • coolie
  • Browserify
  • modules-webmake
  • wreq

Webpack

  • Webpack 官方文档
  • React Webpack cookbook

编译

  • Babel

0 0
原创粉丝点击