由于使用bable7 ,所以直接使用.babelrc 解析react、ts、es6高级语法
.babelrc相关配置如下,此文件位于项目根目录下。
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
["@babel/preset-react"],
["@babel/preset-typescript"]
],
"plugins": [
[
"import",
{
"libraryName": "antd"
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
],
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-syntax-dynamic-import"
]
}
同样需要配置tsconfig.json,此文件位于项目根目录下。内容如下
{
"compilerOptions": {
"outDir": "./dist",
"module": "esnext",
"target": "es5",
"lib": [
"es6",
"dom"
],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowUnreachableCode": true,
"noImplicitAny": false
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
这是基础配置,接下来是配置webpack.config.js,此文件位于项目根目录下
区分了开发和线上环境
if (process.env.NODE_ENV === "development") {
module.exports = require("./config/webpackconfig");
} else {
module.exports = require("./config/webpackconfig");
}
根据webpack.config.js中文件的路径,新建生产和线上的webpack 配置,有几个小知识点,
1、使用了happypack ,直接打包了babel-loader
2.1、output.path是硬盘文件路径
2.2、output.publicPath配置的是打包文件输出的访问路径
3、const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);这个可以将.tsx中引入的.less 文件拆分出来
4、const HtmlWebpackPlugin = require(“html-webpack-plugin”);可以根据你设置的路径在dist中生成.html模版,并且将3中拆分出来的less 引入到dist/index.html中
5、new webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin(),
这三个是是用于koa-webpack-dev-middleware热更新的,随后配置后端的时候,会再提到
下面是webpack 代码
const path = require("path");
const webpack = require("webpack"); // 加载webpack 中的模块
const HappyPack = require("happypack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const os = require("os");
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const nodeEnv = "development";
module.exports = {
mode: process.env.NODE_ENV,
entry: {
index: [
"@babel/polyfill",
"webpack-hot-middleware/client?noInfo=true",
"./src/index.tsx"
]
},
output: {
path: path.join(__dirname, "../dist"),
publicPath: "/dist/",
filename: "js/[name].js",
chunkFilename: "js/[name].chunk.js"
},
module: {
rules: [
{
test: /\.(js?|ts?|jsx?|tsx?)$/,
exclude: /node_modules/,
use: ["happypack/loader?id=babel"]
},
{
test: /\.(c|le)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: process.env.NODE_ENV === "development"
//reloadAll: true,
}
},
"css-loader",
"postcss-loader",
"less-loader"
]
}
]
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify(nodeEnv),
NODE_LOCATION: JSON.stringify(process.env.NODE_ENV)
}
}),
new HappyPack({
id: "babel",
loaders: [
{
loader: "babel-loader"
}
],
threadPool: happyThreadPool
}),
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[name].css",
ignoreOrder: false
}),
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.html",
inject: true
})
],
resolve: {
//有些不同的模块会区分不同的代码这里决定使用哪份代码,例如es6 and es5
mainFiles: ["index.web", "index"],
modules: [path.resolve(__dirname, "src"), "node_modules"],
// 添加让webpack 解析的后缀 例如 ./entry ,优先匹配entry.ts,entry.tsx,最后是entry.js
extensions: [".ts", ".tsx", ".js", ".json", ".less", ".css"]
},
performance: {
hints: false
}
};
总的来说,react+webpack 前半部分基本上就是这样了
package.json 启动脚本是这样的
"start": "cross-env NODE_ENV=development nodemon --watch 'server_koa.js' -e ts,tsx --exec 'ts-node' ./server_koa.js ",
koa_server.js,在后半部分详细介绍,启动http 服务,做接口请求。
nodemon 检测server_koa.js,支持检测路径’server/**/*’,当使用ts 编写后台时,可以直接重新编译,然后重启ts-node’ ./server_koa.js 服务
======================手动分割线=
koa2 是轻量级的服务器接口
koa2 中没有像express中可以直接使用use,或者get 拦截处理路由,需要使用const Router = require(“koa-router”);做路由分发,也可以自己做这一步,不过麻烦
koa2 中同样没有静态文件分发,需要使用const send = require(“koa-send”);进行react打包的js 和less 进行模版发送,就是webpack 中从.tsx中抽离出来的js 和less 。也有资源说可以使用koa-static,但是,但是我这里加在不出来js和less,报错404.所以最后问同事才了解到koa-send。koa-static是继承实现koa-send,所以问题不大。
下面就是这一块代码,/dist/是webpack 中 output.publicpath 路径,检测系统访问的时候分发文件资源,
/test/是项目文件,就是react route 的路径,也就是浏览器地址栏的路径
这里配置中间件的格式,返回我们配置的模版,所有的访问路径都会经过这个中间件
router.get("/dist/*", async (ctx, next) => {
await send(ctx, ctx.path);
});
// app.use(static(__dirname + "/dist/", { extensions: ["html"] }));
router.get("/test/*", async (ctx, next) => {
ctx.type = "html";
ctx.body = fs.createReadStream("dist/index.html");
await next();
});
nodemon 是检测server,也监控node后台代码。检测到改变就重新编译
const webpackDevMiddleware = require("koa-webpack-dev-middleware");
const webpackHotMiddleware = require("koa-webpack-hot-middleware");
const wdm = webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPath
});
app.use(wdm);
app.use(webpackHotMiddleware(compiler));
这两块内容来对.tsx 文件进行热更新。webpackDevMiddleware这个板块中的必须注明 publicPath: config.output.publicPath这个路径,否则不能进行文件热更新,因为找不到更改的文件对应的板块,出现的问题就是hot-update.json找不到,这个链接中注明了publicPath必须写明的原因。
还有就是config/webpackconfig.js 中使用的那三个插件
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
注意npm 官网上的这三个插件名称不正确,会直接在webpack 编译中直接报错,拿着报错信息自行百度一下就会有结果。
下面的是server_koa.js完整代码
const Koa = require("koa");
const app = new Koa();
const Router = require("koa-router");
// const koaBody = require("koa-body");
// const static = require("koa-static");
// const path = require("path");
const send = require("koa-send");
const fs = require("fs");
const webpack = require("webpack");
const webpackDevMiddleware = require("koa-webpack-dev-middleware");
const webpackHotMiddleware = require("koa-webpack-hot-middleware");
const config = require("./webpack.config");
const compiler = webpack(config);
const router = new Router();
router.get("/dist/*", async (ctx, next) => {
await send(ctx, ctx.path);
});
// app.use(static(__dirname + "/dist/", { extensions: ["html"] }));
router.get("/test/*", async (ctx, next) => {
ctx.type = "html";
ctx.body = fs.createReadStream("dist/index.html");
await next();
});
const wdm = webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPath
});
app.use(wdm);
app.use(webpackHotMiddleware(compiler));
app.use(router.routes());
app.listen(8081);
console.log("Server running on port 8081");
或者把webpack打包的这一块抽成中间件
const Koa = require("koa");
const app = new Koa();
const Router = require("koa-router");
const send = require("koa-send");
const fs = require("fs");
const webpackMiddleware = require("./config/middleware/webpack-dev-hot-middleware");
app.use(webpackMiddleware.wdm());
app.use(webpackMiddleware.whm());
const router = new Router();
router.get("/dist/*", async (ctx, next) => {
await send(ctx, ctx.path);
});
router.get("/test/*", async (ctx, next) => {
ctx.type = "html";
ctx.body = fs.createReadStream("dist/index.html");
await next();
});
app.use(router.routes());
app.listen(8081);
console.log("Server running on port 8081");
对应的webpack 中间件./config/middleware/webpack-dev-hot-middleware
const webpack = require("webpack");
const webpackDevMiddleware = require("koa-webpack-dev-middleware");
const webpackHotMiddleware = require("koa-webpack-hot-middleware");
const config = require("../../../webpack.config");
const compiler = webpack(config);
const webpackMiddleware = {
wdm() {
return webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPath
});
},
whm() {
return webpackHotMiddleware(compiler);
}
};
module.exports = webpackMiddleware;
接下来,就是配置koat-route ,与之对应的就是ajax 访问的接口,然后数据传输
在server_koa.ts中封装route ,
// 接口访问
let controller = fs.readdirSync(__dirname + '/controller');
controller.forEach((element) => {
let module = require(__dirname + '/controller/' + element);
router.use('/ajax', module.routes(), module.allowedMethods());
console.log(router, 'router')
})
这里就是在server.koa.ts 中读取controller 下定义的全部模块,还有一层dao 文件,这里是将数据库操作和业务层代码分开,在controller 中解析request ,读取dao 层中的数据库操作语句,返回结果。封装response。
这里是controller 中login 下的index.ts 文件
这两部极易遇到404,检查是否写了 next();检查是否在context 返回了没有->
ctx.set("Content-Type", "application/json")
ctx.body = JSON.stringify({
code: 200,
data: { username: response[0].username },
message: '登录成功',
})
const login = require('koa-router')();
//这个引入是将同为login 目录下的其他路由引入到index.ts。因为在server_koa.ts 中读取的只是index.ts中的路由
const loginout = require('./loginout');
// 读取数据库操作,将结果返回过来
const daoLogin = require('../../dao/login');
// login
login.post('/login', async (ctx, next) => {
const user = ctx.request.body;
const response = await daoLogin.loginCheck(user, next);
if (response && response.length > 0) {
ctx.set("Content-Type", "application/json")
ctx.body = JSON.stringify({
code: 200,
data: { username: response[0].username },
message: '登录成功',
})
} else {
ctx.set("Content-Type", "application/json")
ctx.body = JSON.stringify({
code: 202,
message: '密码错误',
})
}
})
//可以引入其他文件的但是属于本模块的路由,类似于logout 这样的功能
login.use('/loginout', loginout.routes());
module.exports = login;
export { };
这是dao 层的login
const db = require('../../../config/middleware/database');
const loginCheck = (param, next) => {
let sql = 'select username, userid from users where username= ? and password = ?',
value = [param.username, param.password];
return db.query(sql, value);
}
module.exports = {
loginCheck
}
//index.ts
let mysql = require('mysql');
let pool = mysql.createPool(require('./config'));
let connect = () => pool.getConnection(function (err, connection) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
let query = (sql, values) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
reject(err)
} else {
connection.query(sql, values, (err, rows) => {
if (err) {
reject(err)
} else {
resolve(rows)
}
connection.end()
})
}
})
})
};
module.exports = {
connect,
query
}
//confg.ts
let dbConfig = {
host: 'localhost',
user: '*******',
password: '**********',
database: '*****',
port: 3306,
multipleStatements: true//允许多条sql同时执行
};
module.exports = dbConfig;
如果已经装好mysql 了,这里稍微改一下就可以了。
下载好,直接装就行了,连接过程总可能会遇到这个错误:Client does not support authentication protocol requested by server; consider upgrading MySQL client。
这个是解决办法:https://www.cnblogs.com/zichuan/p/9203129.html
一些基本的数据库操作
PATH="$PATH":/usr/local/mysql/bin