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 运行生产模式
- React+Webpack+Router搭建React基础工程
- Webpack构建React基础工程
- [React项目总结] 基于 webpack 搭建前端工程基础篇
- webpack搭建react
- webPack+react 环境搭建
- webpack+babel+react搭建
- React +webpack 基础配置
- react+redux+router+webpack+immutable.js框架
- Webpack + react-router 按需加载
- webpack+react-router按需加载入门
- webpack-dev-server 支持 react-router BrowserHistory
- React router+ webpack实现:按需加载
- 从零开始,教你用Webpack构建React基础工程
- 从零开始,教你用Webpack构建React基础工程
- webpack-3 react-router-4 react-15.6 升级记录
- express+webpack+react搭建项目
- react + webpack + ES6 环境搭建
- React + webpack 快速搭建项目
- Python 元组(Tuple)操作详解
- ASP.NET Core利用原生服务控制反转注入泛型类
- Devops到底是什么?
- eclipse创建工作集(working set)
- hashMap底层源码解密
- React+Webpack+Router搭建React基础工程
- 动力节点-王勇-百度云-DRP项目
- vijos 1059 积木城堡 01背包记录方案
- [LeetCode]2 Add Two Numbers
- mongo db 安装
- Excel 总结
- 1127. ZigZagging on a Tree 解析
- socket通讯须知
- (转)Android dialog圆角显示及解决出现的黑色棱角.(友情提示)