简单介绍一下webpack
webpack的功能很多,打包js\css\html,压缩,编译less\sass,自动生成版本号等等,因为可以使用CommonJS等规范,可以和react很好地配合使用。
它的使用方法比gulp要复杂,但是能做的事情也要比gulp更多一些~~
webpack自己有插件,常用的比如commonsPlugin、UglifyJsPlugin、ExtractTextPlugin、HtmlWebpackPlugin
等,实际项目中,也需要使用node自带的一些模块,比如path、glob
等,这些模块具体在下面讲。
项目目录
经过webpack打包后,生成的html、css、js文件都放在dist文件夹下,以dist/css、dist/js、dist/html
这样的方式。
express搭建
安装和使用就不说了,网上教程很详细,这里只提一点,express4.0
版本以上,把命令工具分离出来到express-generator
了,需要另外安装,npm install -g express-generator
,否则项目搭建会出问题滴。
node安装react
这个环境中,react是使用node安装的,npm install react --save-dev
,由于react 0.14版本把react拆分为react
和react-dom
,因此还需要将react-dom安装一下,npm install react-dom --save-dev
。
在文件中直接引用就可以:
var React = require('react');
var ReactDom = require('react-dom');
分离以后,react package
中包含React.createElement、createClass、Component, .PropTypes,Children
这些API,而react-dom
中包含ReactDOM.render、unmountComponentAtNode、findDOMNode
。
注意对应使用React
或ReactDOM
调用。
另注意,react声明组件时,第一个字母必须大写。
webpack的安装和配置
安装
- 安装webpack:
npm install webpack --save-dev
- 安装各种loader:
webpack需要的loader有:html-loader、css-loader、style-loader、url-loader、jsx-loader、babel-loader等
,安装方式npm install ***** --save-dev
,在安装这些loader之前,需要先安装file-loader
,在安装babel-loader
之前,需要先安装babel-core
。 - 安装插件:
常用插件commonsPlugin、UglifyJsPlugin、ExtractTextPlugin、HtmlWebpackPlugin
等,ExtractTextPlugin、HtmlWebpackPlugin
需要先npm install安装
,commonsPlugin、UglifyJsPlugin
为webpack自带,无需额外安装。
多页面打包
当项目是单页面时,可以直接写死entry的入口文件,也可以直接写死打包出的html页面的名称和路径,但当项目是多页面时,把入口文件和html打包名称路径等写死就非常麻烦了,这时可以使用node模块glob
。使用方式见下面demo~
自动生成js和css的引用
html页面里不需要手动引入js和css,这里webpack配置了生成带引用的html,会自动把所需引用加入到html中
所以一个简单的html就像这样,不需要写和
标签
配置
贴一个webpack.config.js
的demo~
/*
功能:打包文件,提取公共部分,并生成带js\css引用的html页面
打包前的文件,静态资源放在public/src下,html在views下
打包后统一放在public/dist里
使用的node模块:path、glob
使用的webpack插件:commonsPlugin ExtractTextPlugin HtmlWebpackPlugin
网上有说开启webpack观察者模式会导致内存占用过高,可以用gulp调用webpack的方式解决
但是貌似这个项目并没有这种问题~
*/
/**************************引入webpack***********************************/
var webpack = require('webpack');
/**************************引入node模块path、glob*******************************/
var path = require('path');
//该模块用于返回匹配指定模式的文件名或目录,
//由于本项目为多页面,因此需要多个入口文件和多个html
//需要这个模块获取文件放入数组,需要时循环
var glob = require('glob');
/****************************设置默认路径*******************************/
/*
设置默认路径distPath,在module.exports中的output的path处使用
所有打包出的文件,路径都在这个基础上继续
写在这里是因为比较突出。。直接写在output的path当然也是可以的
*/
var distPath = path.join(__dirname,'/public/dist/');
/*****************************声明getEntry函数**************************/
/*
该函数使用glob的方法,拆分文件路径
目前有两个地方使用了这个方法:
1. 循环view文件夹,生成多个html打包的conf配置;
2. 循环js入口文件
由于module.exprots中的entry项是个对象,因此这里把entry设为{}
参数url为传进来的需要获取的文件目录的路径
最后返回的entry的格式:
{
login : './public/src/js/Entry/user/login.js',
register : './public/src/js/Entry/user/register.js'
*******
}
在自己的实际项目中,按实际情况可以有其他处理方式~
*/
var getEntry = function (url) {
var entry = {};
glob.sync(url).forEach(function (name) {
/*
循环所有文件,对文件名做处理,并放入entry数组中,返回entry
*/
if(name.indexOf('views') != -1){
//是html页面
var n = name.substring(8,name.lastIndexOf('.'));
}else{
//不是html页面 这里实际上只有js页面需要处理
var n = name.substring((name.lastIndexOf('/') + 1),name.lastIndexOf('.'));
}
var name = __dirname + name.substring(1);
if(n.indexOf('.') != 0){
entry[n] = name;
}
});
return entry;
};
/******************************使用webpack的插件********************************/
/*
commonsPlugin,把公共部分提取出来
*/
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin({
// 提取出的公共模块的名称,js会打包为common.js,css为common.css
// common.js会按照module.exports中output的路径打包,
// common.css会按照ExtractTextPlugin插件设置的路径打包
//如果按照网上的例子直接写为common.js,
//会导致提取出来的公共css被打包成css/js/common.js/css
name: 'common',
//chunks----从哪些文件中提取
//目前这里不需要设置,因为所有js文件都需要被提取
//chunks: getEntry('./public/src/js/Entry/*/**.js')
});
/*
ExtractTextPlugin,打出单独的css包
*/
var ExtractTextPlugin = require("extract-text-webpack-plugin");
/*
HtmlWebpackPlugin,打包html
*/
var HtmlWebpackPlugin = require('html-webpack-plugin');
/***********************设置module.exports中的plugins***************************/
/*
定义一个数组,module.exports中的plugins项可以直接使用这个数组
*/
var plugins = [];
/*
添加打包公共文件插件的调用
*/
plugins.push(commonsPlugin);
/*
调用ExtractTextPlugin,把单独的css打到dist/css/下面,该路径也是从distPath开始
[name]为引用这个css文件的js文件的入口文件打包后的名字,即入口文件output后的名字
*/
plugins.push(new ExtractTextPlugin("css/[name].css"));
/*
加载jq,否则项目中使用jquery会报错'$ is not defined',
用jquery('#**')这样的方式使用jquery当然也是不行滴~
*/
plugins.push(new webpack.ProvidePlugin({
$: 'jquery'
}));
/**********************获取所有html文件,生成HtmlWebpackPlugin插件需要的conf配置**************************/
/*
调用getEntry,传递路径为打包前的html文件
*/
var pages = getEntry('./views/*/**');
/*循环pages*/
for(var chunkname in pages){
/*
这里使用webpack的HtmlWebpackPlugin插件
conf为该插件的配置项
将每个文件的conf循环插入plugins,可以实现多页面打包
*/
var conf = {
filename: 'html/'+chunkname+'.html', //打包后的html存放路径,也是从distPath开始
template: pages[chunkname], //文件模板,就是打包前的html文件
inject: true, //可以对head和body做修改
//设置该页面引用的文件,只有符合条件的才会被引用
//这里是'common'和页面同名的js\css文件
chunks : ['jquery','react','react-dom','common', chunkname.substring(chunkname.indexOf('/')+1)],
minify: { //压缩HTML
removeComments: true,
collapseWhitespace: false
},
hash: true, //版本号,打出来的html中对css和js的引用自带版本号
}
//把每个conf循环插入plugins
plugins.push(new HtmlWebpackPlugin(conf));
}
/****************************添加对js和css的压缩*************************/
plugins.push(new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
except: ['$', 'require'] //排除关键字,不然会把这些都压缩替换
})
)
/**********************module.exports的entry配置*******************************/
//获取所有入口文件
var entryJS = getEntry('./public/src/js/Entry/*/**.js');
/*
把react\react-dom-jquery单独打包,如果不写的话,会把这些都打到common.js里
可以解决common.js体积过大的问题~
*/
entryJS['react'] = ['react'];
entryJS['react-dom'] = ['react-dom'];
entryJS['jquery'] = ['jquery'];
/****************************webpack的总体配置******************************/
module.exports = {
//入口文件,这里循环所有入口文件,不需要每个都写出来
entry: entryJS,
output: {
//打包文件存放的绝对路径,html、css、js都会按这个路径打包
path: distPath,
//网站运行时的访问路径,不设置的话,打包出的html中的默认引用的路径会是相对路径
publicPath: "/public/dist/",
//打包后的文件名
filename: 'js/[name].js'
},
resolve: {
//require文件的时候不需要写后缀了,可以自动补全
extensions: ['', '.js', '.jsx','.css']
},
module: {
loaders: [//定义一系列加载器
{test: /\.html$/,loader: "html"}, /*html*/
{test: /\.js$/, loader: "babel"}, /*es6 to es5*/
{test: /\.jsx$/,loader: 'jsx-loader'}, /*jsx to js,es5 to es6*/
{test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")}, /*css to css*/
{test: /\.(jpg|png)$/, loader: "url?limit=8192"}, //limit=8192表示图片大小单位是k 小于这个值走内联大于这个值走外联 /*images 打包*/
{test: /\.less$/, loader: "style!css!less"} /*less to css*/
]
},
plugins: plugins , //使用插件
//watch: true //开启观察者模式
};
未添加的功能:
图片打包,按需加载,react热替换
后面陆续加上~