react-router+webpack+gulp路由实例
背景:新项目要开始了,有一种想要在新项目中使用react的冲动,应该也是一个单页面的应用,单页应用就涉及到一个路由的问题.于是最近在网上找了蛮多关于react-router的文章,也遇到了许多的坑,经过不懈的探求之后,今天终于搞出了个成功的demo......特此记录
1.项目结构
本demo采用react+webpack+gulp的组合进行开发,主要的js文件app.js放在js这个目录下.
index.html的结构如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react Router</title>
<!--<script src="build/react.js"></script>-->
<!--<script src="build/react-dom.js"></script>-->
<!--<script src="build/browser.min.js"></script>-->
</head>
<body>
<div id="container1"></div>
<script src="http://localhost:8080/assets/bundle.js"></script>
<!--<script src="/build/bundle.js"></script>-->
</body>
</html>
接下来说说我遇到的第一个坑:
最开始我是直接将app.js用script标签引入的,但是由于app.js里面采用了es6的写法,import什么的,导致在浏览器中直接运行index.html一直报错require is undefined
ok,在网上找了一些资料,后来我就采用了webpack,它可以自动帮你寻找依赖,所以也不需要在index.html顶部引入react.js, react-dom.js,以及browser.min.js了.
2.webpack的使用(webpack.config.js)
关于webpack的安装,请大家参照官网,由于本demo中用到了webpack的热更新,()即更新了js代码,无需手动刷新浏览器即可看到最新的效果),所以还安装了webpack-dev-server
http://webpack.github.io/docs/webpack-dev-server.html
类似于gulp的使用,webpack使用时需要在项目根目录下键一个webpack.config.js的配置文件.配置文件里面的参数的含义在官网上都很清楚.
var webpack = require('webpack');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:8080/', // WebpackDevServer host and port
'webpack/hot/dev-server', // "only" prevents reload on syntax errors
"./js/app.js"
],
output: {
path: '/build',
publicPath: "http://localhost:8080/assets/",
filename: "bundle.js",
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/,
// loader: 'babel' ,
loaders: ['react-hot', 'babel?presets[]=es2015&presets[]=react'], }]
// [
// {test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/},
// {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
// {test: /\.css$/, loader: "style!css"}]
},
// externals: [
// {
// react: {
// root: 'React',
// commonjs2: 'react',
// commonjs: 'react',
// amd: 'react'
// }
// }
// ],
resolve: {
extensions: ['', '.js', '.json']
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
上述代码中,简要解释一下如下参数的含义:
entry 是页面中的入口文件,本demo的入口文件是js/app.js.
output: 是指页面通过webpack打包后生成的目标文件放在什么地方去,本势力中根目录下有一个build文件夹,一旦执行webpack,该文件夹内会有一个build.js文件;
此外,注意到还有一个publicPath的属性,在index.html中,我将引用的js文件指向这个路径,就可以达到热更新的效果.
resolve: 定义了解析模块路径时的配置,常用的就是extensions; 可以用来指定模块的后缀,这样在引入模块时就不需要写后缀,会自动补全。
plugins: 定义了需要使用的插件,比如commonsPlugin在打包多个入口文件时会提取公用的部分,生成common.js,而HotModuleReplacementPlugin就是用来做热更新的;
module.loaders:是文件的加载器,比如我们之前react需要在页面中引入jsx的js源码到页面上来,然后使用该语法,但是通过webpack打包后就不需要再引入JSXTransformer.js;看到上面的加载器;比如jsx-loader加载器就是代表JSXTransformer.js的,还有style-loader和css-loader加载器;
test是一个正则表达式,符合要求的才会采用loader指定的加载器.
注意了!第二坑来了,网上有的帖子将loaders直接写成loaders:['react-hot','babel'],会报错,说你语法错误,所以一定要写成loaders:['react-hot','babel?presets[]=es2015&presets[]=react'].
exclude应该是将这个目录下的js文件排除在外.
3.webpack-dev-server部署一个迷你服务器(server.js)
/**
* Created by huangyq0811 on 2016/8/29.
*/
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config'); new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(8080, 'localhost', function (err, result) {
if (err) console.log(err);
console.log('Listening at localhost:8080');
});
4.react-router路由
官网的demo也很清晰:
https://www.npmjs.com/package/react-router
app.js文件代码如下:
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, Link, IndexLink,hashHistory } from 'react-router'
const ACTIVE = { color: 'red' };
const App = React.createClass({
render(){
return(
<div>
<h3>Ricky12</h3>
<ul>
<li><Link to="/about" activeStyle={ACTIVE}>/about</Link></li>
<li><Link to="/inbox" activeStyle={ACTIVE}>/inbox</Link></li>
<li><Link to="/messages" activeStyle={ACTIVE}>/messages</Link></li>
<li><IndexLink to="/" activeStyle={ACTIVE}>/ IndexLink</IndexLink></li>
</ul>
{this.props.children}
</div>
)
} });
const About = React.createClass({
render() {
return <h3>About</h3>
}
});
const Inbox = React.createClass({
render() {
return (
<div>
<h3>Inbox</h3>
<Link to="inbox/msg" activeStyle={ACTIVE}>/msg</Link>
{this.props.children}
</div>
)
}
});
const Message = React.createClass({
render() {
return <h3>Message</h3>
}
});
const Msg = React.createClass({
render() {
return <h3>this is msg info</h3>
}
}); render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="messages" component={Message} />
<Route path="inbox" component={Inbox}>
<Route path="msg" component={Msg} />
</Route>
</Route>
</Router>
), document.getElementById("container1"));
代码分析:当你在webstorm中启动了sever.js这个文件之后,在浏览器地址栏输入localhost:8080/index.html,由于没有加任何路径,路由会默认分配到App这个组件来展示,并且之后其他的组件都将作为子页面嵌套在App这个组件里面
如果你看到如下和面,并且控制台没有报错,那么成功了
<Route path="inbox" component={Inbox}><Route path="msg" component={Msg}/></Route>
这句代码意味着:你在浏览器地址栏输入localhost:8080/index.html#/inbox/msg时,页面将首先加载Inbox这个组件,随后再将Msg这个组件加载在Inbox里面,形如:
<Inbox><Msg/></Inbox>
而且为了能够呈现Inbox里面的子组件,我们在构造Inbox这个组件时,在return时不能少了{this.props.children}.
最后再附上点击了列表inbox之后再点击msg的效果图:
5.差点漏了gulp
其实gulp在本demo中用处不大,但是如果你是引用的静态文件,而又想根据修改的代码实时更新js文件,那么就可以用到gulp的watch方法了:
/**
* Created by huangyq0811 on 2016/8/29.
*/
var gulp = require('gulp');
var webpack = require('gulp-webpack');
var webpackConfig = require('./webpack.config');
gulp.task("webpack1", function() {
var myConfig = Object.create(webpackConfig);
return gulp
.src('/js/app.js')
.pipe(webpack(myConfig))
.pipe(gulp.dest('./build'));
});
gulp.task("default",function () {
gulp.watch('./js/app.js', ['webpack1']);
});
上述代码中,一旦你在命令行中执行了 gulp这个命令,那么当你更改了app.js的代码并保存之后,都会触发webpack1的这样一个gulp任务
6.为了方便下载依赖包,我将package.json贴在下面,只需要运行npm install即可
{
"name": "ricky-react-router",
"version": "2.7.0",
"description": "A complete routing library for React",
"files": [
"*.md",
"docs",
"es6",
"lib",
"umd"
],
"main": "lib/index",
"jsnext:main": "es6/index",
"repository": "reactjs/react-router",
"homepage": "https://github.com/reactjs/react-router#readme",
"bugs": "https://github.com/reactjs/react-router/issues",
"scripts": {
"build": "npm run build-cjs && npm run build-es",
"build-cjs": "rimraf lib && cross-env BABEL_ENV=cjs babel ./modules -d lib --ignore '__tests__'",
"build-es": "rimraf es6 && cross-env BABEL_ENV=es babel ./modules -d es6 --ignore '__tests__'",
"build-umd": "cross-env NODE_ENV=development webpack modules/index.js umd/ReactRouter.js",
"build-min": "cross-env NODE_ENV=production webpack -p modules/index.js umd/ReactRouter.min.js",
"lint": "eslint examples modules scripts tools *.js",
"start": "node examples/server.js",
"test": "npm run lint && npm run test-node && npm run test-browser",
"test-browser": "cross-env NODE_ENV=test karma start",
"test-node": "cross-env NODE_ENV=test mocha --compilers js:babel-register tests.node.js"
},
"authors": [
"Ryan Florence",
"Michael Jackson"
],
"license": "MIT",
"dependencies": {
"babel-preset-react": "^6.11.1",
"history": "^2.1.2",
"hoist-non-react-statics": "^1.2.0",
"invariant": "^2.2.1",
"loose-envify": "^1.2.0",
"react-router": "^2.7.0",
"warning": "^3.0.0",
"webpack-dev-server": "^1.15.0"
},
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0"
},
"devDependencies": {
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-dev-expression": "^0.2.1",
"babel-plugin-istanbul": "^1.0.3",
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-1": "^6.13.0",
"babel-register": "^6.11.6",
"babel-preset-stage-0": "^6.3.13",
"bundle-loader": "^0.5.4",
"codecov": "^1.0.1",
"cross-env": "^2.0.0",
"css-loader": "^0.23.1",
"eslint": "^3.2.0",
"eslint-config-rackt": "^1.1.1",
"eslint-plugin-react": "^5.2.2",
"expect": "^1.20.2",
"express": "^4.14.0",
"express-urlrewrite": "^1.2.0",
"gzip-size": "^3.0.0",
"karma": "^1.1.2",
"karma-browserstack-launcher": "^1.0.1",
"karma-chrome-launcher": "^1.0.1",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.1.1",
"karma-mocha-reporter": "^2.0.5",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.7.0",
"mocha": "^2.5.3",
"pretty-bytes": "^3.0.1",
"qs": "^6.2.1",
"react": "^15.3.0",
"react-addons-css-transition-group": "^15.3.0",
"react-addons-test-utils": "^15.3.0",
"react-dom": "^15.3.0",
"rimraf": "^2.5.4",
"style-loader": "^0.13.1",
"webpack": "^1.13.1",
"webpack-dev-middleware": "^1.6.1"
},
"browserify": {
"transform": [
"loose-envify"
]
},
"tags": [
"react",
"router"
],
"keywords": [
"react",
"react-component",
"routing",
"route",
"routes",
"router"
]
}
react-router+webpack+gulp路由实例的更多相关文章
- React router 4 获取路由参数,跨页面参数
1. match通过路径 <Route path="/path/:name" component={example} /> 路由组件内获取参数使用 this.props ...
- React Router学习笔记(转自阮一峰老师博客)
React Router是一个路由库,通过管理URL来实现组件切换和状态转变. 1.安装和使用 $ npm install -S react-router 在使用时,作为React组件导入 impor ...
- webpack+react+antd 单页面应用实例
React框架已经火了好长一段时间了,再不学就out了! 对React还没有了解的同学可以看看我之前的一篇文章,可以快速简单的认识一下React.React入门最好的实例-TodoList 自己从开始 ...
- React Router 4.0 + webpack 实现组件按需加载
网上关于React Router 4.0的按需加载文章有很多,大致的思路都一样,但是其实具体实现起来却要根据自己的实际情况来定,这里主要介绍一下我的实现方式. 主要方式是通过Route组件的rende ...
- react router 4.0以上的路由应用
thead>tr>th{padding:8px;line-height:1.4285714;border-top:1px solid #ddd}.table>thead>tr& ...
- react router @4 和 vue路由 详解(七)react路由守卫
完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 12.react路由守卫? a.在之前的版本中,React Router 也提供了类似的 ...
- react router @4 和 vue路由 详解(全)
react router @4 和 vue路由 本文大纲: 1.vue路由基础和使用 2.react-router @4用法 3.什么是包容性路由?什么是排他性路由? 4.react路由有两个重要的属 ...
- 链接(跳转)<router-link> 和 路由实例Router
<router-link>和<router-link>传入的对象参数中包含path路径.name命名路由.params路径参数.query ?查询,并且如果提供了 path,p ...
- React Router 4.0 实现路由守卫
在使用 Vue 或者 Angular 的时候,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的 beforeEnter 函 ...
随机推荐
- 关于iOS10 Xcode8真机测试项目出现的问题 "code signing is required for product type 'xxxxx' in SDK 'iOS 10.0"..
昨天用真机测试项目出现这样的错误,在网上搜集了一些信息,所以将自己的经验分享出来帮助更多的人. 第一步: 检查你的1和2是否填写正确,如果你是运行别人的项目,BundleIdentifier要和你的X ...
- start
------siwuxie095 start 启动另一个窗口运行指定的程序或命令 语法: START ["title"] [/D path] [/I] [/MIN] [/MAX] ...
- 反射,System.Type类
http://m.blog.csdn.net/blog/woddle/40623333 两个现实中的例子:1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况.这是如何做到 ...
- Nginx-->基础-->理论-->001:Nginx基本介绍
一.nginx基本介绍 传统上基于进程或者线程模型架构的web服务通过每进程或者每线程处理并发连接请求,这势必毁在网络和I/O操作时产生阻塞,其另外一个必然结果则是对内存和CPU的利用率低下,产生一个 ...
- Bootstrap插件系列——Bootstrap-table初始化、分页、客户端搜索、服务端搜索
又好久不写博客,最近项目都是用的bootstrap的样式,不出意外,应该是要在bootstrap的道路上越走越远了,所以下定决心,把bootstrap的插件都好好学学. 昨天写了boostrap-ta ...
- docke部署mysql
#1 docker pull mysql #2 docker run -v /data/var/mysql/:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=k ...
- 关于Linkedlist 和 ArrayDeque的讨论
转自:http://blog.csdn.net/f2006116/article/details/51375470 其中:我们要讨论的LinkedList和ArrayDeque都是实现Deque接口, ...
- 安装 CentOS 后的系统配置及软件安装备忘
安装 CentOS 后的系统配置及软件安装备忘 // */ // ]]> 安装 CentOS 后的系统配置及软件安装备忘 Table of Contents 1 Linux 自举过程 1.1 ...
- PHP入门教程-开发环境搭建
1.PHP简介: PHP是能让你生成动态网页的工具之一.PHP网页文件被当作一般HTML网页文件来处理并且在编辑时你可以用编辑HTML的常规方法编写PHP. 2.学习需要基础: a.HTML b.Ja ...
- JMeter压力测试入门教程[图文]
Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测试但后来扩展到其他测试领域. 它可以用于测试静态和动态资源例如静态文件. ...