React+Webpack+Router搭建React基础工程

来源:互联网 发布:青岛电视台网络电视 编辑:程序博客网 时间:2024/05/17 03:25

       本文主要介绍React+Webpack+Router搭建React基础工程的简单方式。

      React 起源于 Facebook 的内部项目,因为该公司对市场上所有的前端MVC框架都不满意,就决定自己写一套,用来构建Instagram。

       React主要用于构建UI。你可以在React里传递多种类型的参数,如声明代码,帮助你渲染出UI、也可以是静态的HTML DOM元素、也可以传递动态变量、甚至是可交互的应用组件。

       特点:

       1.声明式设计:React采用声明范式,可以轻松描述应用。

       2.React通过对DOM的模拟,最大限度地减少与DOM的交互。

3.灵活:React可以与已知的库或框架很好地配合。


如果你想对本文中的React、webpack、router有更加深入的了解,请访问以下网站进行深入的学习:

1.React官方中文文档:http://reactjs.cn/react/docs/getting-started-zh-CN.html(大多数文章后缀名加入zh-CN会变为中文)

2.webpack中文指南 :http://webpackdoc.com/loader.html

3.react-router中文文档:http://www.uprogrammer.cn/react-router-cn/


好了,废话不多说,下面介绍运用React+Webpack+Router搭建React基础工程,目录结构如图所示:(bundle.js和server.bundle.js为构建生成的文件)


package.json文件配置:

{  "name": "webpack-react",  "version": "1.0.0",  "description": "",  "main": "./justice/index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",    "start:dev": "webpack-dev-server --inline --content-base build --history-api-fallback",    "start:prod": "npm run build && node server.bundle.js",    "build:client": "webpack",    "build:server": "webpack --config webpack.server.config.js",    "build": "npm run build:client && npm run build:server",    "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build --history-api-fallback"  },  "keywords": [    "webpack"  ],  "author": "",  "license": "ISC",  "devDependencies": {    "babel-core": "^6.18.2",    "babel-loader": "^6.2.7",    "babel-plugin-react-transform": "^2.0.0",    "babel-preset-es2015": "^6.6.0",    "babel-preset-react": "^6.5.0",    "babel-preset-stage-0": "^6.16.0",    "body-parser": "^1.4.3",    "css-loader": "^0.21.0",    "express": "^4.4.5",    "extract-text-webpack-plugin": "^1.0.1",    "file-loader": "^0.9.0",    "jquery": "^3.1",    "less": "^2.7.2",    "less-loader": "^2.2.3",    "react-dom": "^15.3.2",    "react-redux": "^4.4.6",    "react-router": "^3.0.0",    "redux-devtools": "^3.3.1",    "style-loader": "^0.13.0",    "url-loader": "^0.5.7",    "webpack": "^1.13.3",    "webpack-dev-server": "^1.16.2"  },  "dependencies": {    "babel-core": "^6.18.2",    "babel-loader": "^6.2.7",    "babel-plugin-react-transform": "^2.0.0",    "babel-preset-es2015": "^6.3.13",    "babel-preset-react": "^6.3.13",    "babel-preset-stage-0": "^6.16.0",    "body-parser": "^1.4.3",    "compression": "^1.6.2",    "css-loader": "^0.21.0",    "express": "^4.14.0",    "file-loader": "^0.9.0",    "if-env": "^1.0.0",    "jquery": "^3.1",    "react": "^15.3.2",    "react-dom": "^15.3.2",    "react-redux": "^4.4.6",    "react-router": "^3.0.0",    "redux-devtools": "^3.3.1",    "style-loader": "^0.13.0",    "url-loader": "^0.5.7",    "webpack": "^1.13.3",    "webpack-dev-server": "^1.16.2"  }}

webpack.config.js构建客户端
var path = require('path');var webpack = require('webpack');var ExtractTextPlugin = require("extract-text-webpack-plugin");var config = {    //构建入口    entry:['webpack/hot/dev-server', path.resolve('', './justice/index.js')],    //构建出口 path:打包文件存放的绝对路径 filename:打包后的文件名 publicPath:运行时的访问路径    output: {        path: path.resolve('', 'build'),        filename: 'bundle.js',        publicPath: '/'    },    module: {        loaders: [            //es6 es7 react加载器            {                test: /\.js?$/,                exclude: /node_modules/,                loader: 'babel-loader',                query: {                    presets: ["es2015",'stage-0',"react"]                }            },            {                test: /\.jsx?$/,                exclude: /node_modules/,                loader: 'babel-loader',                query: {                    presets: ["es2015",'stage-0',"react"]                }            },            //css解析器            {                test:  /\.css$/,                loader: 'style!css'            },            //style解析器            {                test: /\.less$/,                use: [                    'style-loader',                    { loader: 'css-loader', options: { importLoaders: 1 } },                    'less-loader'                ]            },            //图片处理 小于8K按base64处理            { test: /\.(png|jpg)$/,                 loader: 'url-loader?limit=8192'            }        ]    },    babel: {        presets: ['es2015','stage-0','react']    },    resolve:{        //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名        extensions:['','.js','.json']    },    //插件配置  ExtractTextPlugin:提取样式插件    plugins: process.env.NODE_ENV === 'production' ? [        new webpack.optimize.DedupePlugin(),        new webpack.optimize.OccurrenceOrderPlugin(),        new webpack.optimize.UglifyJsPlugin(),        new ExtractTextPlugin("styles.css")    ] : [        new webpack.HotModuleReplacementPlugin(),        new ExtractTextPlugin("styles.css")    ]};module.exports = config;
server.js 服务端配置
var express=require('express');var path=require('path');var compression=require('compression');var react=require('react');var match=require('react-router');var RouterContext=require('react-router');var renderToString=require('react-dom/server');var app=express();//must be first! 文件压缩app.use(compression());app.use(express.static(path.join(process.cwd(), 'build')));app.get('*',function(req,res){    res.sendFile(path.join(process.cwd(),'build','index.html'));});function renderPage(appHtml) {    return `    <!doctype html public="storage">    <html>    <meta charset=utf-8/>    <div id=app>${appHtml}</div>    <script src="/bundle.js"></script>   `}var PORT = process.env.PORT || 8080app.listen(PORT, function(){    console.log('Production Express server running at localhost:' + PORT);});
 webpack.server.config.js 构建服务端:
var fs = require('fs')var path = require('path')module.exports = {    entry: path.resolve(__dirname, 'server.js'),    output: {        filename: 'server.bundle.js'    },    target: 'node',    // keep node_module paths out of the bundle    externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([        'react-dom/server', 'react/addons',    ]).reduce(function (ext, mod) {        ext[mod] = 'commonjs ' + mod        return ext    }, {}),    node: {        __filename: true,        __dirname: true    },    module: {        loaders: [            {                test: /\.js?$/,                exclude: /(node_modules|bower_components)/,                loader: 'babel',                query: {                    presets: ['es2015', 'react','stage-0']                }            },            {                test: /\.jsx?$/,                exclude: /node_modules/,                loader: 'babel-loader',                query: {                    presets: ["es2015",'stage-0',"react"]                }            },            {                test:  /\.css$/,                loader: 'style!css'            },            { test: /\.(png|jpg)$/,                loader: 'url-loader?limit=8192'            }        ]    }}
webpack部分到此为止,接下来我们继续写react和router部分:
index.html
<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">    <meta name="renderer" content="webkit">    <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />    <meta content="telephone=no" name="format-detection" />    <meta name="apple-mobile-web-app-capable" content="yes">    <meta name="apple-mobile-web-app-status-bar-style" content="#035c9b">    <!--不构建压缩css,为了开发中的调试,直接引用-->    <link rel="stylesheet" href="/css/bootstrap.css"  />    <link rel="stylesheet" href="/css/bootstrap-theme.css"  />    <link rel="stylesheet" href="/css/theme.css"  />    <link rel="stylesheet" href="/css/fixed-data-table.css"  />    <link rel="stylesheet" href="/css/rc-tree/index.css"  />    <link rel="stylesheet" href="/css/rc-dialog/index.css"  />    <link rel="stylesheet" href="/css/rc-calendar/index.css"  />    <link rel="stylesheet" href="/css/rc-time-picker/index.css"  /></head><body><div id="content"></div></body><!--iframe模式 因为在package.json中配置了inline模式,此行注释 --><!--<script src="http://localhost:8080/webpack-dev-server.js"></script>--><!--如果使用browserHistory 这里请用/bundle.js --><!-- 其他也要用 /index.css 这种形式 --><script src="/bundle.js"></script></html>
从上面的webpack.config.js中可知,我们构建的入口为index.js,index.js也必为路由的入口,配置如下:
index.js
var React=require('react');var ReactDOM=require('react-dom');var Router=require('react-router').Router;//hashHistory url中带有#号,browserHistory不带有#号var hashHistory=require('react-router').hashHistory;var browserHistory=require('react-router').browserHistory;var routes=require('./routes.js').routes//url上的userName 和 repoName 会传到this.props.params中//IndexRoute 当没有其他明确url时会首先renderReactDOM.render((    <Router routes={routes} history={browserHistory}></Router>), document.getElementById('content'))
我们发现index.js引用了routes即路由的集合,这个集合存在于routes.js
routes.js的内容如下:
var React=require('react');var Route= require('react-router').Route;var IndexRoute=require('react-router').IndexRoute;var Home=require('./home').Home;var Welcome=require('./page/welcome').Welcome;var Tree=require('./page/tree.jsx').Tree;var Silder=require('./page/silder.jsx').Silder;var Calendar=require('./page/calendar.jsx').Calendar;var Dialog=require('./page/dialog.jsx').Dialog;var Table=require('./page/table.jsx').Table;var Datepicker=require('./page/datepicker').Datepicker;var $=require('jquery');//即进入路由时触发的函数var enterFun=function(nextState,replace){    if(nextState.location.pathname=='/'){        $('#home').addClass('active');    }    if(nextState.location.pathname!='/'){        $('#home').removeClass('active');    }}//component代表使用的组件 IndexRoute为首页路由 path为路径 路由按层级进入,一开始进入Home组件 然后组合首页路由同时进入Welcome组件var routes=(    <Route onEnter={enterFun} path="/" component={Home} >        <IndexRoute onEnter={enterFun} component={Welcome}></IndexRoute>        <Route onEnter={enterFun} path="/tree"  component={Tree}></Route>        <Route onEnter={enterFun} path="/table" component={Table}></Route>        <Route onEnter={enterFun} path="/calendar"  component={Calendar}></Route>        <Route onEnter={enterFun} path="/dialog"  component={Dialog}></Route>        <Route onEnter={enterFun} path="/silder"  component={Silder}></Route>        <Route onEnter={enterFun} path="/datepicker"  component={Datepicker}></Route>    </Route>);exports.routes=routes;
 首页路由welcome.js的内容如下
var React=require('react');var Link= require('react-router').Link;var IndexLink=require('react-router').IndexLink;var Welcome = React.createClass({    render : function(){        return (            <div>               欢迎来到React<br/>                构建方式为React+webpack+router            </div>        );    }})exports.Welcome=Welcome;
Home.js的内容如下   
var React=require('react');var Link= require('react-router').Link;var IndexLink=require('react-router').IndexLink;var Header=require('./header.js').Header;var Footer=require('./footer.js').Footer;var Navigation=require('./nav.js').Navigation;var Menu=require('./menu.js').Menu;var Welcome=require('./page/welcome.js').Welcome;var Home = React.createClass({    render : function(){        return (            <div className="pagewrap">                <Header name='React门户'/>                <Navigation />                <div className="layout-l-r">                    <Menu/>                    <section className="main">                        <ol className="breadcrumb">                            <li><a href="#">主页</a></li>                            <li><a href="#">数据分析</a></li>                            <li className="active">表格</li>                        </ol>                        <div className="main-view col-xs-12">                            {this.props.children||<Welcome/>}                        </div>                    </section>                </div>                <Footer />            </div>        );    }})exports.Home=Home;
接下来是menu.js 为访问路由的方式: to='xxx'中的路径与route中的path对应
var React=require('react');var Link= require('react-router').Link;var IndexLink=require('react-router').IndexLink;//<Link to='silder'     activeClassName="active"  className="list-group-item">React SilderBar</Link>var Menu = React.createClass({    render : function(){        return (            <section className="leftside">                <div className="list-group navfun">                    <Link to='/' id='home'   className="list-group-item">Home</Link>                    <Link to='tree'       activeClassName="active"  className="list-group-item">React Tree</Link>                    <Link to='table'      activeClassName="active"  className="list-group-item">React Table</Link>                    <Link to='calendar'   activeClassName="active"  className="list-group-item">React Calendar</Link>                    <Link to='dialog'     activeClassName="active"  className="list-group-item">React Dialog</Link>                </div>            </section>        );    }})exports.Menu=Menu;
 header.js(footer.js结构与之形式相似,这里不赘述)
var React=require('react');var Header = React.createClass({    render : function(){        return (            <header>                <h1>{this.props.name}</h1>            </header>        );    }})exports.Header=Header;

table.jsx(其他组件与之结构相似,这里不赘述)
    
var React=require('react');var PropTypes=require('react').PropTypes;var Link= require('react-router').Link;var IndexLink=require('react-router').IndexLink;var myTree = React.createClass({    render() {        return (<div style={{ margin: '0 20px' }}>           tree        </div>);    }});exports.Tree=myTree;

至此,一个简单的react+webpack+router的基础工程搭建完毕
第一步:执行npm install 安装node modules
第二步:执行npm start 或npm run start:dev 运行dev模式
     
             执行npm run start:prod 运行生产模式
 






0 0
原创粉丝点击