Webpack 作为前端构建工具,对于大型网站开发,大大提升了开发效率。要使用webpack需要先安装webpack工具;

先来看一个最简单的命令

$ webpack main.js bundle.js

该命令将 main.js 输出到 bundle.js 。

通常,都不会这样直接使用使用,而是在项目根目录下进行打包配置,配置文件默认为webpack.config.js。

// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};

之后,直接在命令行中使用 webpack 就能进行打包了!

除了直接使用 webpack 进行打包之外,还可以对打包命令进行一些选择性的配置:

  • webpack – for building once for development
  • webpack -p – for building once for production (minification)
  • webpack --watch – for continuous incremental build
  • webpack -d – to include source maps
  • webpack --colors – for making things pretty

同样,这些配置也可以写进 package.json 配置文件中

// package.json
{
// ...
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
// ...
}

1. entry

// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};

entry 除了使用一个单一的 js 文件之外,还可以使用多个 js 文件;

module.exports = {
entry: {
bundle1: './main1.js',
bundle2: './main2.js'
},
output: {
filename: '[name].js'
}
};

2. Babel-loader

Loader 是源代码转换预处理器(more info). 例如, Babel-loader 可以将 JSX/ES6 转换成 JS 文件. 参见官方文档:loaders.

// main.jsx is a JSX file.

const React = require('react');
const ReactDOM = require('react-dom'); ReactDOM.render(
<h1>Hello, world!</h1>,
document.querySelector('#wrapper')
);

index.html

<html>
<body>
<div id="wrapper"></div>
<script src="bundle.js"></script>
</body>
</html>

webpack.config.js

module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
},
]
}
};

module.loaders 用于指定 loaders. 上面的代码片段使用了 babel-loader,也用到了babel-preset-es2015babel-preset-react 用来转换 ES6 和 React。也可以使用如下的query的方式来配置:

module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
}

3. CSS-loader

Webpack 使我们可以通过 require 引用一个css文件并结合css-loader处理之后输出成一个模块。

main.js

require('./app.css');

app.css

body {
background-color: blue;
}

index.html

<html>
<head>
<script type="text/javascript" src="bundle.js"></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>

webpack.config.js

module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.css$/, loader: 'style-loader!css-loader?modules' },
]
}
};

注意,这里使用了两个loader来转换css文件。 CSS-loader 用来读取CSS文件, Style-loader用来插入样式到网页中. 不同的loader用 ! 来连接.

在浏览器中浏览网页,index.html中已经插入了样式表。

<head>
<script type="text/javascript" src="bundle.js"></script>
<style type="text/css">
body {
background-color: blue;
}
</style>
</head>

4. Image loader

Webpack 还可以通过 require 引用图片文件。

main.js

var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1); var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);

index.html

<html>
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>

webpack.config.js

module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
]
}
};

这里使用了 url-loader 来转换图片文件. 如果图片小于 8192 bytes 将会被转换成 Data URL; 否则将会被转换成普通的URL. ? 用来给url-loader传入参数.

两张不同大小的图片会被转换成不同的格式如下:

<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">

5. CSS Module

css-loader?modules 表示打开 CSS Modules 的功能。它表示module中定义的css样式默认是局部作用域;如果需要转换成全局作用域可以通过 :global(.abc) (more info)

index.html

<html>
<body>
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hello Webpack</h2>
<div id="example"></div>
<script src="./bundle.js"></script>
</body>
</html>

app.css

.h1 {
color:red;
} :global(.h2) {
color: blue;
}

main.jsx

var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css'); ReactDOM.render(
<div>
<h1 className={style.h1}>Hello World</h1>
<h2 className="h2">Hello Webpack</h2>
</div>,
document.getElementById('example')
);

webpack.config.js

module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules'
}
]
}
};

6. UglifyJs Plugin

Webpack 有插件支持用来扩展更多的需求。 UglifyJs Plugin 将会最小化输出的js文件.

main.js

var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');

webpack.config.js

var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new uglifyJsPlugin({
compress: {
warnings: false
}
})
]
};

运行项目,main.js 将被输出成如下格式:

var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")

注意:如果需要结合使用到postcss,webpack.config.js文件需要有一些小的修改如下:

var values = require("postcss-modules-values");
var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin; module.exports = {
entry: __dirname + "/index.js",
output: {
path:"public",
publicPath: "/",
filename: "bundle.js"
},
module: {
loaders:[
{
test: /\.js$/,
exclude: /node_modules/,
loader:'babel-loader'
},
{
test: /\.css$/,
loader: "style-loader!css-loader?modules!postcss-loader"
}
]
},
plugins:[
new uglifyJsPlugin({
compress:{
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
test:/\.css$/,
options: {
postcss:[values]
}
})
]
};

备注: UglifyJsPlugin还可以对一些指定的变量不进行混淆

plugins: [
new webpack.optimize.UglifyJsPlugin({
mangle: {
except: ['$super', '$', 'exports', 'require']
//以上变量‘$super’, ‘$’, ‘exports’ or ‘require’,不会被混淆
},
compress: {
warnings: false
}
})
]

7. HTML Webpack Plugin and Open Browser Webpack Plugin

下面来看如何加载第三方插件

html-webpack-plugin 可以创建index.html, open-browser-webpack-plugin 可以打开一个浏览器窗口当 Webpack 加载完成之后。

npm install html-webpack-plugin open-browser-webpack-plugin webpack-dev-server --save

main.js

document.write('<h1>Hello World</h1>');

webpack.config.js

var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin'); module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
};

运行 webpack-dev-server.

$ webpack-dev-server

现在不需要手动创建index.html文件,也不需要去打开浏览器窗口了,一切由webpack为我们包办了!

可能遇到的错误: Error: Cannot find module 'webpack/lib/node/NodeTemplatePlugin' ,解决办法:在项目中重新安装webpack。

8. Environment flags

可以通过一些配置来对开发环境和正式环境进行一些不同的操作;

main.js

document.write('<h1>Hello World</h1>');

if (__DEV__) {
document.write(new Date());
}

webpack.config.js

var webpack = require('webpack');

var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
}); module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [devFlagPlugin]
};

运行webpack打包并输入环境变量配置:

# Linux & Mac
$ env DEBUG=true webpack-dev-server # Windows
$ set DEBUG=true
$ webpack-dev-server

process.env 默认为一个空对象,通过 env DEBUG=true命令 为env.DEBUG赋值。

9. Code splitting

对于大型web网站,不可能将所有的js文件都放到一个文件中一次性加载, Webpack 允许我们将js文件进行分割。

首先,你需要使用 require.ensure 来定义分割点 (official document)

// main.js
require.ensure(['./a'], function(require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});

require.ensure 告诉 Webpack,./a.js 文件应该从bundle.js文件中分割出来并编译到一个单独的文件中。

// a.js
module.exports = 'Hello World';

现在webpack将会自动进行编译打包,不需要再进行额外的配置。

webpack.config.js

module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};

从表象上看,没有任区别,但实际上webpack将main.js和a.js编译到两个不同的文件中了,分别是bundle.js和1.bundle.js文件,当需要用到的时候再加载1.bundle.js文件;

10. Code splitting with bundle-loader

另一个代码分割的方法是使用 bundle-loader.

// main.js

// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js'); // To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});

require('bundle-loader!./a.js') 告诉 Webpack 需要从另外的js文件中去加载 a.js。webpack的行为将和上面相同。

11. Common chunk

当多个script文件需要使用到相同的chunk的时候,可以将这个公用的模块通过CommonsChunkPlugin提取到单独的文件中。

// JQ01.js
var $ = require("jquery");
$('#a').text("001"); // JQ02.js
var $ = require("jquery");
$('#b').text("002");

上面的两个不同的组件中,都同时需要用到 JQuery,甚至会有更多的组件也会如此,此时可以将 JQuery 提取出来,放置到一个公共的 js 文件中。

index.html

<html>
<body>
<div id="a"></div>
<div id="b"></div>
<script src="vendor.js"></script>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>

webpack.config.js

var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");

module.exports = {
entry: {
bundle1: "./JQ01.js",
bundle2: "./JQ02.js",
vendor: ["jquery"] // option
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin({
name: 'vendor',
filename: "vendor.js"
})
]
};

随着库越来越大,vendor文件也变得越来越大,于是考虑打包成两个vendor,把和react相关的库打包成一个vendor,其他的库打包成另外一个vendor。

...
entry: {
"vendor1": ["react", "react-dom", "react-router", "react-router-redux", "react-redux", "redux"],
"vendor2": ["jquery"],
"app": "./js/index.js"
},
...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ["vendor2", "vendor1"],
minChunks: Infinity
})
],
...

有两个需要注意的地方:

  • 在CommonsChunkPlugin里面,vender的顺序要反着来,要和加载顺序相反。比如你想按vendor1,vendor2的顺序加载,entry里面写的是vendor1,vendor2,在CommonsChunkPlugin里面要写vendor2,vendor1。
  • output.filename一定不要写死了,要配置成可替换的,类似filename: '[name].js'形式。

12. Vendor chunk

也可以通过 CommonsChunkPlugin 来分割提取出js库。

main.js

var $ = require('jquery');
$('h1').text('Hello World');

index.html

<html>
<body>
<h1></h1>
<script src="vendor.js"></script>
<script src="bundle.js"></script>
</body>
</html>

webpack.config.js

var webpack = require('webpack');

module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js'
},
plugins: [
new CommonsChunkPlugin({
name: 'vendor',
filename: "vendor.js"})
]
};

ProvidePlugin


如果你希望一个module可以作为一个变量使用到其它地方,比如使用jQuery的 $ ,我们可以在任何地方使用而不需要通过 require("jquery"),这就需要用到 ProvidePlugin (Official doc).

// main.js
$('h1').text('Hello World');

webpack.config.js

var webpack = require('webpack');

module.exports = {
entry: {
app: './main.js'
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
};

13. Exposing global variables

如果我们想使用一些全局变量,但又不想把它们包含在webpack中,这时候可以通过在webpack.config.js中 配置 externals 来实现 official document

data.js.

var data = 'Hello World';

将data数据暴露成全局变量

// webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
]
},
externals: {
// require('data') is external and available
// on the global var data
'data': 'data'
}
};

现在,通过 var data = require('data') 可以将data.js输出到模块变量中。但实际上data是一个全局变量。

// main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom'); ReactDOM.render(
<h1>{data}</h1>,
document.body
);

14. Hot Module Replacement

Hot Module Replacement (HMR) 当网页发生改变的时候,不需要手动刷新页面。结合webpack-dev-server有两种方式来打开 HMR。

(1) 在命令中指定 --hot 和 --inline

$ webpack-dev-server --hot --inline

Meaning of the options:

  • --hot: adds the HotModuleReplacementPlugin and switch the server to hot mode.
  • --inline: embed the webpack-dev-server runtime into the bundle.
  • --hot --inline: also adds the webpack/hot/dev-server entry.

(2) 配置 webpack.config.js.

  • add new webpack.HotModuleReplacementPlugin() to the plugins field
  • add webpack/hot/dev-server and webpack-dev-server/client?http://localhost:8080 to the entry field

webpack.config.js

var webpack = require('webpack');
var path = require('path'); module.exports = {
entry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080',
'./index.js'
],
output: {
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
},
include: path.join(__dirname, '.')
}]
}
};
Now launch the dev server.
$ webpack-dev-server

在浏览器中打开 http://localhost:8080 查看网页。保持网页打开,对网页修改一些内容,观察浏览器是否发生改变;

App.js

import React, { Component } from 'react';

export default class App extends Component {
render() {
return (
<h1>Hello World</h1>
);
}
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));

index.html

<html>
<body>
<div id='root'></div>
<script src="/static/bundle.js"></script>
</body>
</html>

15. React router

参考 React-router 官方示例

+---------------------------------------------------------+
| +---------+ +-------+ +--------+ |
| |Dashboard| | Inbox | |Calendar| Logged in as Jane |
| +---------+ +-------+ +--------+ |
+---------------------------------------------------------+
$ webpack-dev-server --history-api-fallback 

参考连接:

Webpack 官方文档 : http://webpack.github.io/docs/configuration.html

Webpack 配置示例的更多相关文章

  1. Webpack配置示例和详细说明

    /* * 请使用最新版本nodejs * 默认配置,是按生产环境的要求设置,也就是使用 webpack -p 命令就可以生成正式上线版本. * 也可以使用 webpack -d -w 命令,生成用于开 ...

  2. webpack配置示例

    var webpack = require('webpack'); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('commo ...

  3. webpack配置这一篇就够

    最近看了一篇好文,根据这个文章重新梳理了一遍webpack打包过程,以前的一些问题也都清楚了,在这里分享一下,同时自己也做了一些小的调整 原文链接:http://www.jianshu.com/p/4 ...

  4. vue-cli中webpack配置详解

    vue-cli是构建vue单页应用的脚手架,命令行输入vue init <template-name> <project-name>从而自动生成的项目模板,比较常用的模板有we ...

  5. webpack 配置分离css插件

    以css配置示例,less与sass同理 1. 使用旧版的ExtractTextPlugin插件 安装 npm install extract-text-webpack-plugin@next --s ...

  6. 通用、封装、简化 webpack 配置

    通用.封装.简化 webpack 配置 现在,基本上前端的项目打包都会用上 webpack,因为 webpack 提供了无与伦比强大的功能和生态.但在创建一个项目的时候,总是免不了要配置 webpac ...

  7. Element源码:项目初始化和webpack配置

    0x00.项目初始化 由于整个过程像素级 copy element,所以将不使用vue-cli初始化项目. 创建项目 新建一个空的文件夹,使用npm init 来初始化项目,并安装vue模块. 修改目 ...

  8. [webpack] 配置react+es6开发环境

    写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...

  9. webpack配置详解

    webpack配置详解 先点个赞吧,再挨个点下面的连接,觉得不值这个赞的回来骂我啊. Webpack傻瓜式指南(一) Webpack傻瓜指南(二)开发和部署技巧 Webpack傻瓜式指南 原生的官网详 ...

随机推荐

  1. WPF 自定义 MessageBox (相对完善版 v1.0.0.6)

    基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当你不得不弹出一个消息框通知用户消息时(虽然很不建议在程序中频繁 ...

  2. 在Gulp中使用BrowserSync

    博客已迁移至http://zlwis.me. 很早就听说过BrowserSync,也看过一些相关文章,可就是没用过.之前一直在用Gulp开发项目,每次编写完Sass后还要用按F5刷新页面看效果,想想也 ...

  3. CentOs6.5中安装和配置vsftp简明教程[转]

    CentOs6.5中安装和配置vsftp简明教程 林涛 发表于:2017-3-17 10:10 分类:WebServer 标签: 101次 一.vsftp安装篇 复制代码代码如下: # 安装vsftp ...

  4. BugPhobia准备篇章:Beta阶段前后端接口文档

    0x00:序言 Two strangers fell in love, Only one knows it wasn’t by chance. To the searching tags, you m ...

  5. JAVA自学日记——Part Ⅲ

    终于来到了可视化窗口制作的部分了,从学习JAVA之前,到开始入手学习,一直到现在,都在盼望着有一天可以自己写出一款有界面而且是很美观的应用程序,今天算是一个真正开始的时间节点,值得纪念. 内容有很多, ...

  6. 51单片机,keilc51,如何使用data变量超过128怎么办

    将堆栈指针SP指向128之后.如果你定义了数组.将数组定义为Idata.很难想象单个变量使用,你能用尽128个data类内存单元.如果真的用尽了,那只有将访问频率低的内存单元放到idata类去.总之, ...

  7. <构建之法>前三章读后感—软件工程

    本教材不同于其他教材一贯的理知识直接灌溉,而是以对话形式向我们传授知识的,以使我们更好地理解知识点,更加清晰明确. 第一章 第一章的概述中,书本以多种方式,形象生动地向我们阐述了软件工程的内容,也让我 ...

  8. Internet History, Technology and Security (Week 7)

    Week 7 Technology: Application Protocols Welcome to Week 7 of IHTS. This week has less material than ...

  9. charles使用教程 干货~

    大部分内容来自前辈们的摘写,博客园是怎么去转载其他好的博呢~ 言归正传,教程看过后还是自己再来一遍理解和操作才会更加深刻. Charles 是在 Mac/WIN下常用的网络封包截取工具,在做移动开发时 ...

  10. 软工网络15团队作业8——敏捷冲刺日志的集合贴(Beta阶段)

    Beta阶段 第 1 篇 Scrum 冲刺博客 第 2 篇 Scrum 冲刺博客 第 3 篇 Scrum 冲刺博客 第 4 篇 Scrum 冲刺博客 第 5 篇 Scrum 冲刺博客 第 6 篇 Sc ...