express+webpack+react搭建項目

簡單介紹一下webpack

webpack的功能不少,打包js\css\html,壓縮,編譯less\sass,自動生成版本號等等,由於能夠使用CommonJS等規範,能夠和react很好地配合使用。
它的使用方法比gulp要複雜,可是能作的事情也要比gulp更多一些~~
webpack本身有插件,經常使用的好比commonsPlugin、UglifyJsPlugin、ExtractTextPlugin、HtmlWebpackPlugin等,實際項目中,也須要使用node自帶的一些模塊,好比path、glob等,這些模塊具體在下面講。css

項目目錄

通過webpack打包後,生成的html、css、js文件都放在dist文件夾下,以dist/css、dist/js、dist/html這樣的方式。html

express搭建

安裝和使用就不說了,網上教程很詳細,這裏只提一點,express4.0版本以上,把命令工具分離出來到express-generator了,須要另外安裝,npm install -g express-generator,不然項目搭建會出問題滴。node

node安裝react

這個環境中,react是使用node安裝的,npm install react --save-dev,因爲react 0.14版本把react拆分爲reactreact-dom,所以還須要將react-dom安裝一下,npm install react-dom --save-dev
在文件中直接引用就能夠:react

var React = require('react');
var ReactDom = require('react-dom');

分離之後,react package中包含React.createElement、createClass、Component, .PropTypes,Children這些API,而react-dom中包含ReactDOM.render、unmountComponentAtNode、findDOMNode
注意對應使用ReactReactDOM調用。
另注意,react聲明組件時,第一個字母必須大寫。jquery

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~webpack

自動生成js和css的引用

html頁面裏不須要手動引入js和css,這裏webpack配置了生成帶引用的html,會自動把所需引用加入到html中

因此一個簡單的html就像這樣,不須要寫<link><script>標籤es6

配置

貼一個webpack.config.js的demo~web

/*
功能:打包文件,提取公共部分,並生成帶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熱替換
後面陸續加上~express

相關文章
相關標籤/搜索