express+webpack+react搭建项目

简单介绍一下webpack

webpack的功能很多,打包js\css\html,压缩,编译less\sass,自动生成版本号等等,因为可以使用CommonJS等规范,可以和react很好地配合使用。
它的使用方法比gulp要复杂,但是能做的事情也要比gulp更多一些~~
webpack自己有插件,常用的比如commonsPlugin、UglifyJsPlugin、ExtractTextPlugin、HtmlWebpackPlugin等,实际项目中,也需要使用node自带的一些模块,比如path、glob等,这些模块具体在下面讲。

项目目录

790606-20160613153150526-463152715.jpg

经过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拆分为reactreact-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
注意对应使用ReactReactDOM调用。
另注意,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中
790606-20160613175130729-1992395522.png
所以一个简单的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') != -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热替换
后面陆续加上~

转载于:https://www.cnblogs.com/feeiluuo/p/5580806.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值