react-router+webpack+gulp路由實例

  背景:新項目要開始了,有一種想要在新項目中使用react的衝動,應該也是一個單頁面的應用,單頁應用就涉及到一個路由的問題.因而最近在網上找了蠻多關於react-router的文章,也遇到了許多的坑,通過不懈的探求以後,今天終於搞出了個成功的demo......特此記錄

  1.項目結構

  

  本demo採用react+webpack+gulp的組合進行開發,主要的js文件app.js放在js這個目錄下.css

  index.html的結構以下: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>

  接下來講說我遇到的第一個坑:node

  最開始我是直接將app.js用script標籤引入的,可是因爲app.js裏面採用了es6的寫法,import什麼的,致使在瀏覽器中直接運行index.html一直報錯require is undefinedreact

  ok,在網上找了一些資料,後來我就採用了webpack,它能夠自動幫你尋找依賴,因此也不須要在index.html頂部引入react.js, react-dom.js,以及browser.min.js了.webpack

  2.webpack的使用(webpack.config.js)

  關於webpack的安裝,請你們參照官網,因爲本demo中用到了webpack的熱更新,()即更新了js代碼,無需手動刷新瀏覽器便可看到最新的效果),因此還安裝了webpack-dev-servergit

  http://webpack.github.io/docs/webpack-dev-server.htmles6

  相似於gulp的使用,webpack使用時須要在項目根目錄下鍵一個webpack.config.js的配置文件.配置文件裏面的參數的含義在官網上都很清楚.github

  

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()
    ]
};

  上述代碼中,簡要解釋一下以下參數的含義:web

  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"
  ]
}
相關文章
相關標籤/搜索