现代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
使用的是browserHistory
。react
的用法可参考这里,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
这里使用bluebird
的promisify
方法将NodeJS风格的API fs.stat
转化成返回Promise对象的方法,这个是为配合koa
的yield
而为,详见这里
同样利用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/about
、http://127.0.0.1:5000/features
,即可看到路由切换的效果。
本篇源代码地址
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- select 进阶查询
- Codeforces Round #627 (Div. 3) E. Sleeping Schedule (DP)
- PAT (Advanced Level) Practice 1144 The Missing Number (20分)
- JDBC 基础操作
- Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) C. Remove Adjacent
- MySQL 存储过程
- MySQL 约束
- MySQL 中的流程控制语句
- MySQL 权限操作
- MySQL 事务
- Java 随机生成四则运算式并生成答案
- MySQL 常用函数汇总
- Leetcode 698. 划分为k个相等的子集
- java数据结构与算法-快速排序
- 线上环境 Linux 系统调用追踪