• 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"
      ]
    }
  • 相关阅读:
    table首行固定
    JavaScript获取当前日期,昨天,今天日期以及任意天数间隔日期
    Struts2二级菜单联动
    Servlet和Struts2同时使用
    最近的感想
    java.lang.NoClassDefFoundError: javax/el/ELResolver 问题解决
    Event Loop、函数式编程、IO多路复用、事件驱动、响应式、
    Git 的使用(一)
    Linux 硬链接与软链接 目录结构
    并发、并行、同步、异步相关感念
  • 原文地址:https://www.cnblogs.com/Ricky-Huang/p/5823218.html
Copyright © 2020-2023  润新知