转载

Webpack 指南(整理)

安装

首先要安装 Node.js, Node.js 自带了软件包管理器 npm。用 npm 全局安装 Webpack:

$ npm install webpack -g

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

# 进入项目目录,初始化,创建 package.json。 # 若存在 package.json 文件,则不运行。 $ npm init # 确定已经有 package.json # 安装 webpack 依赖 $ npm install webpack --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.js document.write('It works.')

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

$ webpack entry.js bundle.js

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

It works. 

最终目录结构如下:

. ├── entry.js ├── index.html ├── package.json ├── node_modules

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

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

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

It works.It works from module.js.

最终目录结构如下:

. ├── bundle.js ├── entry.js ├── index.html ├── module.js ├── package.json ├── node_modules

使用 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

除了npm安装模块的时候以外,在任何场景下,loader名字都是可以简写的。例如:安装时必须用全名,即: npm install json-loader ,而在引用 loader 的时候可以使用全名 json-loader ,也可以使用短名 json 。这个命名规则和搜索优先级顺序在 webpack 的 resolveLoader.moduleTemplates api 中定义。

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

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

loader是可以串联使用的,也就是说,一个文件可以先经过A-loader再经过B-loader最后再经过C-loader处理。而在经过所有的loader处理之前,webpack会先取到文件内容交给第一个loader。

接上一节的例子,我们要在页面中引入一个 CSS 文件 style.css ,首先将 style.css 也看成是一个模块,然后用 css-loader 来读取处理(路径处理、import处理等),然后经过 style-loader 处理(包装成JS文件,运行的时候直接将样式插入DOM中)。

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

修改 entry.js

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

安装 loader:

# css-loader:读取 css 文件 # style-loader:将 css 文件插入页面 $ npm install css-loader style-loader --save-dev

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

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

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

$ webpack entry.js bundle.js --module-bind 'css=style!css'

显然,这两种使用 loader 的方式,效果是一样的。最终的目录结构如下:

. ├── bundle.js ├── entry.js ├── index.html ├── module.js ├── node_modules ├── package.json ├── style.css

Loader 进阶

loader还可以接受参数,不同的参数可以让loader有不同的行为(前提是loader确实支持不同的行为),具体每个loader支持什么样的参数可以参考loader的文档。loader的使用有三种方法,分别是:

  • 在require中显式指定,如:

  • 在命令行中指定,如: $ webpack entry.js output.js --module-bind 'css=style!css'

  • 在配置项(webpack.config.js)中指定,如:

第一种显式指定,即在 JS 文件中指定:

require('style!css!./style.css');`

第二种在命令行中指定参数的用法用得较少,可以这样写:

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

使用 --module-bind 指定loader,如果后缀和loader一样,直接写就好了,比如jade表示.jade文件用jade-loader处理,如果不一样,则需要显示指定,如 css=style!css 表示分别使用 css-loaderstyle-loader 处理 .css 文件。

第三种在配置项中指定是最灵活的方式,它的指定方式是这样:

module: {     // loaders是一个数组,每个元素都用来指定loader     loaders: [{         test: //.jade$/,    //test值为正则表达式,当文件路径匹配时启用         loader: 'jade',    //指定使用什么loader,可以用字符串,也可以用数组         exclude: /regexp/, //可以使用exclude来排除一部分文件          //可以使用query来指定参数,也可以在loader中用和require一样的用法指定参数,如`jade?p1=1`         query: {             p1:'1'         }     },     {         test: //.css$/,         loader: 'style!css'    //loader可以和require用法一样串联     },     {         test: //.css$/,         loaders: ['style', 'css']    //也可以用数组指定loader     }] }

配置文件

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

继续我们的案例,创建配置文件 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 = {}; // 后面代码省略

参数详解

entry

entry参数定义了打包后的入口文件,可以是个字符串或数组或者是对象;如果是数组,数组中的所有文件会打包生成一个filename文件;如果是对象,可以将不同的文件构建成不同的文件:

{     entry: {         page1: "./page1",         //支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出         page2: ["./entry1", "./entry2"]     },     output: {         path: "dist/js/page",         publicPath: "/output/",         filename: "[name].bundle.js"     } }

该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下

output

output参数是个对象,定义了输出文件的位置及名字:

output: {     path: "dist/js/page",     publicPath: "/output/",     filename: "[name].bundle.js" }
  • path : 打包文件存放的绝对路径

  • publicPath : 网站运行时的访问路径

  • filename :打包后的文件名

当我们在 entry 中定义构建多个文件时, filename 可以对应的更改为 [name].js 用于定义不同文件构建后的名字。

module

在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等静态文件都是模块,不同模块的加载是通过模块加载器(webpack-loader)来统一管理的。loaders之间是可以串联的,一个加载器的输出可以作为下一个加载器的输入,最终返回到JavaScript上:

module: {         //加载器配置         loaders: [             //.css 文件使用 style-loader 和 css-loader 来处理             { test: //.css$/, loader: 'style-loader!css-loader' },             //.js 文件使用 jsx-loader 来编译处理             { test: //.js$/, loader: 'jsx-loader?harmony' },             //.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理             { test: //.scss$/, loader: 'style!css!sass?sourceMap'},             //图片文件使用 url-loader 来处理,小于8kb的直接转为base64             { test: //.(png|jpg)$/, loader: 'url-loader?limit=8192'}         ]     }
字段 说明
test 表示匹配的资源类型
loaderloaders 表示用来加载这种类型的资源的loader
定义loader的串联关系,多个loader之间用“!”连接起来

此外,还可以添加用来定义png、jpg这样的图片资源在小于10k时自动处理为base64图片的加载器:

{ test: //.(png|jpg)$/,loader: 'url-loader?limit=10000'}

给css和less还有图片添加了loader之后,我们不仅可以像在node中那样 require() js文件了,我们还可以 require() css、less甚至图片文件:

 require('./bootstrap.css');  require('./myapp.less');  var img = document.createElement('img');  img.src = require('./glyph.png');

注意, require() 还支持在资源path前面指定loader,即 require(![loaders list]![source path]) 形式:

require("!style!css!less!bootstrap/less/bootstrap.less"); // “bootstrap.less”这个资源会先被"less-loader"处理, // 其结果又会被"css-loader"处理,接着是"style-loader" // 可类比pipe操作

require() 时指定的loader会覆盖配置文件里对应的loader配置项。

resolve

webpack在构建包的时候会按目录的进行文件的查找, resolve 属性中的 extensions 数组中用于配置程序可以自行补全哪些文件后缀:

 resolve: {         //查找module的话从这里开始查找         root: '/pomy/github/flux-example/src', //绝对路径         //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名         extensions: ['', '.js', '.json', '.scss'],         //模块别名定义,方便后续直接引用别名,无须多写长长的地址         alias: {             AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可             ActionType : 'js/actions/ActionType.js',             AppAction : 'js/actions/AppAction.js'         }     }

然后我们想要加载一个js文件时,只要 require('common') 就可以加载 common.js 文件了。

注意一下, extensions 第一个是空字符串! 对应不需要后缀的情况.

plugin

webpack提供了[丰富的组件]用来满足不同的需求,当然我们也可以自行实现一个组件来满足自己的需求:

plugins: [      //your plugins list  ]

在webpack中编写js文件时,可以通过require的方式引入其他的静态资源,可通过loader对文件自动解析并打包文件。通常会将js文件打包合并,css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中,最好可以独立生成css文件,以外链的形式加载。这时 extract-text-webpack-plugin 插件可以帮我们达到想要的效果。需要使用npm的方式加载插件,然后参见下面的配置,就可以将js中的css文件提取,并以指定的文件名来进行加载。

npm install extract-text-webpack-plugin –-save-dev
plugins: [     new ExtractTextPlugin('styles.css') ]

externals

当我们想在项目中require一些其他的类库或者API,而又不想让这些类库的源码被构建到运行时文件中,这在实际开发中很有必要。此时我们就可以通过配置externals参数来解决这个问题:

 externals: {      "jquery": "jQuery"  }

这样我们就可以放心的在项目中使用这些API了: var jQuery = require(“jquery”) ;

context

当我们在require一个模块的时候,如果在require中包含变量,像这样:

 require("./mods/" + name + ".js");

那么在编译的时候我们是不能知道具体的模块的。但这个时候,webpack也会为我们做些分析工作:

1.分析目录:’./mods’;2.提取正则表达式:’/^.*.js$/’;

于是这个时候为了更好地配合wenpack进行编译,我们可以给它指明路径,像在cake-webpack-config中所做的那样(我们在这里先忽略abcoption的作用):

 var currentBase = process.cwd();  var context = abcOptions.options.context ? abcOptions.options.context :   path.isAbsolute(entryDir) ? entryDir : path.join(currentBase, entryDir);

关于 webpack.config.js 更详尽的配置可以参考 Webpack Configuration 。

开发环境

当项目逐渐变大,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

React 开发环境的配置

Webpack相关:

$ npm install webpack -g $ npm install webpack-dev-server -g # 安装必要的 loader: ## 编译 JSX $ npm install --save-dev babel-loader ## CSS 文件处理 $ npm install --save-dev css-loader style-loader ## React $ npm install --save-dev react-hot-loader

Babel 相关:

$ npm install --save-dev babel-core # 添加 ES6 支持 $ npm install --save-dev babel-preset-es2015 $ npm install --save-dev babel-react
var webpack = require('webpack'); module.exports = {     entry: [       'webpack/hot/only-dev-server',       "./js/app.js"     ],     output: {         path: './build',         filename: "bundle.js"     },     module: {         loaders: [             { test: //.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ },             { test: //.js$/, exclude: /node_modules/, loader: 'babel-loader'},             { test: //.css$/, loader: "style!css" }         ]     },     resolve:{         extensions:['','.js','.json']     },     plugins: [       new webpack.NoErrorsPlugin()     ] };

参考资料:

  • React Webpack Cookbook

  • Babel 入门教程

  • Webpack 中文指南

  • Webpack 官方文档

原文  https://segmentfault.com/a/1190000005690280
正文到此结束
Loading...