Webpack+React多页面应用探索

前言

Webpack非常适用单页面应用,官方和网上都有大量的例子,对于在多页面的应用和实践比较少见。
本文主要以Webpack+React为例来探索在多页面下的开发模式。
主要实现以下几点:

  • 独立的开发服务器
  • 每个页面对应一个入口文件,页面根据入口文件自动生成,并插入对应的css和js
  • 采用React + Es6的方式进行组件模块化开发
  • 资源文件自动打包到对应的目录里

目录结构说明

│ web 
        ├─mock<—————测试数据
        ├─dist<—————编译后的文件
        ├─view<—————生成的html文件
        └─src 开发目录
           ├─app.js<—————全局样式,全局方法
           ├─template.html<—————html模板文件
           ├─common<—————公共资源
           └─view<—————页面资源,每个页面都有独立的img,css,js
            ├─index
            └─about

开发环境

安装Node和NPM,新版本Node已经继承NPM
安装Webpack npm install webpack -g http://webpack.github.io/
安装Babel npm install --global babel-cli

安装npm插件

npm install

相关命令

  • npm run dev 开发模式,访问127.0.0.1:3000/dist/index
  • npm run build 将文件编译,压缩,打包,访问127.0.0.1:3000/view/index查看效果

Webpack配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
var path = require('path');
var glob = require('glob');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var node_dir = path.join(__dirname, './node_modules/');
var HtmlWebpackPlugin = require('html-webpack-plugin');

// 获取所有入口文件
var getEntry = function(globPath) {
var entries = {
vendor: ['jquery','react','react-dom','./src/app'] // 类库
};
glob.sync(globPath).forEach(function(entry) {
var pathname = entry.split('/').splice(-2).join('/').split('.')[0];
entries[pathname] = [entry];
});
console.log(entries);
return entries;
};
// 判断是否是在当前生产环境
var isProduction = process.env.NODE_ENV === 'production';
var entries = getEntry('./src/view/*/*.jsx');
var chunks = Object.keys(entries);
module.exports = {
entry: entries,
output: {
path: path.join(__dirname, './dist'),
filename: isProduction ?'js/[name].[hash:8].js':'js/[name].js',
publicPath: '/dist/',
chunkFilename: 'chunk/[name].chunk.js'
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
},
exclude: node_dir
}, {
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css')
}, {
test: /\.less$/,
loader: ExtractTextPlugin.extract('style', 'css!less')
}, {
test: /\.(png|jpe?g|gif)$/,
loader: 'url?limit=8192&name=img/[hash:8].[ext]'
}, {
//文件加载器,处理文件静态资源
test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file?limit=10000&name=fonts/[hash:8].[ext]'
}]
},
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
alias: {
mod: node_dir
}
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery', // 使jquery变成全局变量,不用在自己文件require('jquery')了
jQuery: 'jquery',
React: 'react',
ReactDOM: 'react-dom'
}),
// 类库统一打包生成一个文件
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: isProduction ? 'js/vendor.[hash:8].js':'js/vendor.js',
minChunks: 3 // 提取使用3次以上的模块,打包到vendor里
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new ExtractTextPlugin(isProduction ? 'css/[name].[hash:8].css':'css/[name].css')
],
devtool: isProduction ? null : 'source-map'
};
// 生成HTML文件
chunks.forEach(function(pathname) {
if (pathname == 'vendor') {
return;
}
var conf = {
title: 'My App',
filename: isProduction? '../view/' + pathname + '.html' : pathname + '.html',
template: './src/template.html',
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: false
}
};
if (pathname in module.exports.entry) {
conf.chunks = ['vendor', pathname];
conf.hash = false;
}
module.exports.plugins.push(new HtmlWebpackPlugin(conf));
});

HTML模板文件

src目录下有个template.html文件,无需引入任何css和js,webpack会自动帮我们打包引入,
<%= htmlWebpackPlugin.options.title %>读取配置好的页面标题

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title> <%= htmlWebpackPlugin.options.title %> </title>
</head>
<body>
<div id="app"></div>
</body>
</html>

最终通过打包,会生成对应入口的html文件,
比如src/view/index/index.js会生成view/index/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> My App </title>
<link href="/dist/css/vendor.abf9657f.css" rel="stylesheet">
<link href="/dist/css/index/index.abf9657f.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="/dist/js/vendor.abf9657f.js"></script>
<script type="text/javascript" src="/dist/js/index/index.abf9657f.js"></script>
</body>
</html>

你会发现相关资源文件都自动引入了,十分便捷。

代码地址:https://github.com/QzhouZ/webpack-react-multiplePage