原文:http://www.cnblogs.com/feeiluuo/p/5580806.html
簡單介紹一下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等
,在安裝這些loader之前,需要先安裝npm install ***** --save-dev
,在安裝file-loader
之前,需要先安裝babel-loader
。babel-core
-
安裝插件:
常用插件
等,commonsPlugin、UglifyJsPlugin、ExtractTextPlugin、HtmlWebpackPlugin
需要先ExtractTextPlugin、HtmlWebpackPlugin
,npm install安裝
為webpack自帶,無需額外安裝。commonsPlugin、UglifyJsPlugin
多頁面打包
當項目是單頁面時,可以直接寫死entry的入口檔案,也可以直接寫死打包出的html頁面的名稱和路徑,但當項目是多頁面時,把入口檔案和html打包名稱路徑等寫死就非常麻煩了,這時可以使用node子產品
glob
。使用方式見下面demo~
自動生成js和css的引用
html頁面裡不需要手動引入js和css,這裡webpack配置了生成帶引用的html,會自動把所需引用加入到html中
是以一個簡單的html就像這樣,不需要寫
<link>
和
<script>
标簽
配置
貼一個
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') != ){
//是html頁面
var n = name.substring(,name.lastIndexOf('.'));
}else{
//不是html頁面 這裡實際上隻有js頁面需要處理
var n = name.substring((name.lastIndexOf('/') + ),name.lastIndexOf('.'));
}
var name = __dirname + name.substring();
if(n.indexOf('.') != ){
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('/')+)],
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熱替換
後面陸續加上~
ITDogFire--sky