现代Web开发系列教程_07

今天结合前面说到的前后端开发知识,做一个小工程,这个小工程并不完全具体的业务功能,但该工程包括前后端,可以作为以后复杂工程的起点。

前端代码

前端代码稍微复杂一点,就先从前端代码开始。

frontend/js/demo6.js

import React from 'react';
import ReactDOM from 'react-dom';
import ReactRouter from 'react-router';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';

class App extends React.Component{
  render(){
    return <div>{this.props.children}</div> ;
  }
}

class Home extends React.Component{
  render(){
    return <h1>Home Page</h1> ;
  }
}

class About extends React.Component{
  render(){
    return <h1>About Page</h1> ;
  }
}

class Features extends React.Component{
  render(){
    return <h1>Features Page</h1> ;
  }
}

document.body.innerHTML = '<div id="reactHolder"></div>';

ReactDOM.render(
  <Router history={browserHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Home} />
      <Route path='about' component={About} />
      <Route path='features' component={Features} />
      <Route path='*' component={Home} />
    </Route>
  </Router>,
  document.getElementById('reactHolder')
);

可以看到就是定义了几个React组件,并用react-router定义了一个很简的路由,这个路由的history使用的是browserHistoryreact的用法可参考这里react-router的用法可参考这里

写前端代码编译脚本

webpack.config.js

const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        demo6 : __dirname + '/frontend/js/demo6.js'
    },
    output: {
        path: __dirname + '/public',
        publicPath: '/',
        filename: 'js/[name].js',
        hotUpdateMainFilename: 'hot-update/[hash].hot-update.json',
        chunkFilename: 'js/chunks/[name].js',
        hotUpdateChunkFilename: 'hot-update/chunks/[id].[hash].hot-update.js',
    },
    plugins: [
        new webpack.SourceMapDevToolPlugin({
            test:      /\.(js|css|less)($|\?)/i,
            filename: '[file].map'
        }),
        new HtmlWebpackPlugin({
          title: 'demo6',
          filename: 'index.html',
          hash : true,
          chunks : ['demo6']
        })
    ],
    module: {
        loaders: [
            {test: /\.(js|jsx)$/, loaders: ["babel"]}
        ]
    },
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    devtool: 'eval'
};

.babelrc

1

{ "presets": ["react", "es2015"] }

上面的webpack编译配置很简单,就是配置把frontend/js/demo6.js编译到public/js/demo6.js,同时生成public/index.html,其引用生成的public/js/demo6.js

利用npm-scripts来进行webpack的调用

"scripts": {
  "wpack": "./node_modules/.bin/webpack --watch --progress"
},

后端代码

backend/server.js

"use strict";

const koa = require('koa');
const serve = require('koa-static');
const sendfile = require('koa-sendfile')
const path = require('path');
const Promise = require('bluebird');
const fs = require('fs');

const statAsync = Promise.promisify(fs.stat);

const app = koa();

app.use(serve(__dirname + '/../public'));

app.use(function *(next){
    let p = path.resolve(__dirname, '..', 'public', this.path);
    let stats = null;
    try{
        stats = yield statAsync(p);
    }catch(ignore){}
    if (!stats) {
        try {
            stats = yield sendfile(this, path.resolve(__dirname, '..', 'public', 'index.html'));
        }catch(ignore){}
        if (!stats) this.throw(404);
    }
});

const port = 5000;

app.listen(port);

console.log("server started on port " + port);

因为前端使用了browserHistory路由,后端要实现类似nginx的try_files逻辑,详情见这里,如果后端是用Java写法,可以考虑使用TryFilesFilter

这里使用bluebirdpromisify方法将NodeJS风格的API fs.stat 转化成返回Promise对象的方法,这个是为配合koayield而为,详见这里

同样利用npm-scripts启动后端server

"scripts": {
  "serve": "node ./backend/server.js"
},

运行测试

打开两个终端,在一个里面执行npm run serve启动后端server,在另一个里面执行npm run wpack启动webpack对前端代码进行编译。最后使用浏览器分别访问http://127.0.0.1:5000/http://127.0.0.1:5000/abouthttp://127.0.0.1:5000/features,即可看到路由切换的效果。

本篇源代码地址

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏九彩拼盘的叨叨叨

将 ES6 代码转换成 ES5

本文介绍用 Gulp 和 Babel 6 来将 ES6 代码转换成 ES5 代码。

752
来自专栏阮一峰的网络日志

窗口管理器 xmonad 教程

开发者最需要的,就是一个顺手的开发环境。 ? 每个人的偏好不一样,我的开发环境是 Fish Shell + Xfce + xmonad + Vim,已经用了好多...

39111
来自专栏iKcamp

iKcamp出品|微信小程序|工具安装+目录说明|基于最新版1.0开发者工具初中级教程分享

第一章:小程序初级入门教程 工具安装 在上一节第 8 步所展示的页面中,可以点击 开发者工具 直接进入到下载页面,也可以直接访问 官网下载地址。然后根据自己的设...

2249
来自专栏Puppeteer学习

一步一步学Vue(十二)

1652
来自专栏睿哥杂货铺

玩转编程语言:基于Node.js构建自定义代码生成器

在真实的软件开发过程中,无论使用何种编程开发语言,都不可避免的会遇到代码重复的问题。如何处理重复的问题,可以选择情怀(手动再敲一遍),也可以选择 Copy-to...

3025
来自专栏Java成神之路

GEF入门实例_总结_04_Eclipse插件启动流程分析

这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们将通过这几个文件来了解Eclipse插件的启动过程。

1144
来自专栏FreeBuf

利用CSS注入(无iFrames)窃取CSRF令牌

CSS相信大家不会陌生,在百度百科中它的解释是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。 ...

2467
来自专栏程序员宝库

Intellij IDEA神器居然还有这些小技巧

Intellij IDEA真是越用越觉得它强大,它总是在我们写代码的时候,不时给我们来个小惊喜。出于对Intellij IDEA的喜爱,我决定写一个与其相关的专...

1874
来自专栏Java技术分享

基于Metronic的Bootstrap开发框架经验总结(6)--对话框及提示框的处理和优化

在各种Web开发过程中,对话框和提示框的处理是很常见的一种界面处理技术,用得好,可以给用户很好的页面体验,Bootstrap开发也一样,我们往往在页面新增、编辑...

2745
来自专栏Micro_awake web

Vue学习2:模板语法

参考:https://cn.vuejs.org/v2/guide/syntax.html,http://www.runoob.com/vue2/vue-temp...

860

扫码关注云+社区

领取腾讯云代金券