一、准备工作
安装 koa、热更新用的 supervisor
PS:安装 Node.js 就不介绍了,最新版本就 ok
npm init -y
cnpm i koa --save
cnpm i supervisor --save-dev
建立入口文件 app.js
./app.js
const Koa = require("koa");
const app = new Koa();
app.listen(3000,()=>{
console.log("server is running..")
});
./package.json
···
"scripts": {
"start": "npm run dev",
"dev": "supervisor -i ./node_modules ./app.js"
},
···
注意 supervisor -i ./node_modules ./app.js 这条命令!
要是不把 ./node_modules 排除掉的话,supervisor 会吃光你的内存,风扇狂转!
二、建立 controller
建立如图所示目录结构
controller 么,先对路由下手就完了 ~
所以,继续下和路由有关的包吧~
cnpm i koa-simple-router --save
ok,我们可以愉快的写 controller 的父类了
./controllers/indexControllers.js
class IndexControllers {
constructor() {
}
actionIndex(ctx, next) {
ctx.body = "koa2 is running~~";
}
}
module.exports = IndexControllers;
继承父类的 controller
./controllers/index.js
const router = require("koa-simple-router");
const IndexController = require("./indexControllers");
const indexController = new IndexController();
module.exports = app => {
app.use(router(_ => {
_.get("/", indexController.actionIndex);
_.get('/index.html', indexController.actionIndex);
}))
};
_.get("/", indexController.actionIndex);
_.get('/index.html', indexController.actionIndex);伪静态
回到入口文件 app.js 注册路由
const Koa = require("koa");
const app = new Koa();
// 注册路由
require("./controllers/index")(app);
app.listen(3000,()=>{
console.log("server is running..")
});
OK! 我们现在应可以启动服务了,
npm start
之后访问本地服务,就可以看到效果了,是不是还有点儿小激动?
三、建立配置文件优化项目
app.js 里面的
app.listen(3000,()=>{console.log("server is running..")});
的3000
扔到入口文件不伦不类,我们可以把它放到另外的位置
项目根目录建立 config 相关文件,如图所示
./config/index.js
const config={
port:3000
};
module.exports(config);
./app.js
const Koa = require("koa");
const app = new Koa();
const config = require("./config");
// 注册路由
require("./controllers/index")(app);
app.listen(config.port, () => {
console.log("server is running..")
});
既然要优化端口,不如把
生产环境的 80 端口
和开发环境的 3000 端口
分开吧
安装 cross-env
cnpm i cross-env --save-dev
改造 package.json 和 config.js
./package.json
···
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development supervisor -i ./node_modules ./app.js"
},
···
./config/index.js
const config = {};
if (process.env.NODE_ENV === "development") {
config.port = 3000;
} else if (process.env.NODE_ENV === "production") {
config.port = 80;
}
module.exports = config;
四、实现 view 层
老规矩,先建立目录吧
那么问题来了,这些静态文件我们得把它们加载进来呀
安装 koa-static
cnpm i koa-static --save
继续改造 config.js
./config/index.js
const path = require("path");
const config = {
staticDir: path.join(__dirname, "..", "assets")
};
if (process.env.NODE_ENV === "development") {
config.port = 3000;
} else if (process.env.NODE_ENV === "production") {
config.port = 80;
}
module.exports = config;
把静态文件加载进来
./app.js
const Koa = require("koa");
const app = new Koa();
const config = require("./config");
const serve = require("koa-static");
// 注册路由
require("./controllers/index")(app);
// 加载静态文件
app.use(serve(config.staticDir));
app.listen(config.port, () => {
console.log("server is running..")
});
五、实现 Model 层
在这里,我们的模板引擎用的是 koa-swig.js
安装模板引擎
cnpm i koa-swig --save
cnpm i co --save
注:
co
是历史遗留问题,用来把koa1
编译成koa2
完善 view 层
./views/layouts/layout.html
这个将会是所有模板的“祖宗”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
{% block head %}
{% endblock %}
{% block link %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
{% block script %}
{% endblock %}
</body>
</html>
./views/index.html
继承了 layout.html
{% extends './layout.html' %}
{% block title %} 图书管理首页 {% endblock %}
{% block link %}
<link rel="stylesheet" href="/styles/index.css">
{% endblock %}
{% block content %}
<div>
<h1>{{content}}</h1>
</div>
{% endblock %}
{% block script %}
<script src="/scripts/index.js"></script>
{% endblock %}
./assets/styles/index.css
css
body{
background: #000;
}
h1{
color:greenyellow;
}
p{
color:yellow;
}
./assets/scripts/index.js
js
const content = "你好koa~~";
console.log(content);
完善 controller 层
./controllers/index.js
class IndexControllers {
constructor() {
}
async actionIndex(ctx, next) {
ctx.body = await ctx.render('index.html',{
content:"hello node!"
});
}
}
module.exports = IndexControllers;
在入口文件注册模板引擎
./config/index.js
const path = require("path");
const config = {
viewDir: path.join(__dirname, "..", "views"), // 把视图层加载引来
staticDir: path.join(__dirname, "..", "assets")
};
if (process.env.NODE_ENV === "development") {
config.port = 3000;
} else if (process.env.NODE_ENV === "production") {
config.port = 80;
}
module.exports = config;
./app.js
const Koa = require("koa");
const app = new Koa();
const config = require("./config");
const serve = require("koa-static");
const render = require("koa-swig");
const co = require("co");
// 注册路由
require("./controllers/index")(app);
// 加载静态文件
app.use(serve(config.staticDir));
// 配置模板引擎
app.context.render = co.wrap(render({
root: config.viewDir, // 把视图层加载引来
autoescape: true,
cache: false, // 缓存
ext: 'html',
writeBody: false
}));
app.listen(config.port, () => {
console.log("server is running..")
});
OK,我们现在再看下
如果你做到这步了,那么胜利的曙光就要降了!
六、安装 babel
有人会问,现在的代码有什么问题吗?,有,而且不少。
大家回到 ./assets/scripts/index.js
文件,如果我新增了一行如下代码,那会怎样呢?
const content = "你好koa~~";
console.log(content);
export default content;
很正常么,因为它不认识啊,另外如果浏览器不支持
es6
语法怎么办?
安装 babel
cnpm i babel @babel-cli --save-dev
cnpm i babel @babel-core --save-dev
cnpm i babel @babel-preset-env --save-dev
项目根目录新建 .babelrc 文件
./.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": "systemjs"
}
]
]
}
完善 package.json
···
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development supervisor -i ./node_modules ./app.js",
"build": "babel ./assets/scripts/index.js -o ./assets/scripts/index-bundle.js"
},
···
npm run build 一下
完善 views/index.html
{% extends './layouts/layout.html' %}
{% block title %} 图书管理首页 {% endblock %}
{% block link %}
<link rel="stylesheet" href="/styles/index.css">
{% endblock %}
{% block content %}
<div>
<h1>{{content}}</h1>
</div>
{% endblock %}
{% block script %}
<script type="module">
import ("/scripts/index.js").then((_) => {
console.log(_.default);
})
</script>
<script type="nomodule" src="https://cdn.bootcss.com/systemjs/6.2.5/system.min.js"></script>
<script type="nomodule">
System.import("/scripts/index-bundle.js").then((_) => {
console.log(_.default);
})
</script>
{% endblock %}
在这里我们引入了万能木块加载器
systemjs
OK,现在我们的第一阶段学习完成了~
七、CSR + SSR
比如我们可以把
vue
当jQuery
用
./views/layouts/layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
{% block head %}
{% endblock %}
{% block link %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
{% block script %}
{% endblock %}
</body>
</html>
./assets/scripts/index.js
const content = "你好koa~~";
console.log(content);
const app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
});
export default content;
./views/index.html
{% extends './layouts/layout.html' %}
{% block title %} 图书管理首页 {% endblock %}
{% block link %}
<link rel="stylesheet" href="/styles/index.css">
{% endblock %}
{% block content %}
<div>
<h1>[[content]]</h1> // 注意!
</div>
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
{% endblock %}
{% block script %}
<script type="module">
import ("/scripts/index.js").then((_) => {
console.log(_.default);
})
</script>
<script type="nomodule" src="https://cdn.bootcss.com/systemjs/6.2.5/system.min.js"></script>
<script type="nomodule">
System.import("/scripts/index-bundle.js").then((_) => {
console.log(_.default);
})
</script>
{% endblock %}
注意!vue 和 swig 的模板引擎的标识符不能冲突
所以我们还要改下配置文件
./app.js
const Koa = require("koa");
const serve = require("koa-static");
const render = require("koa-swig");
const config = require("./config");
const co = require("co");
const app = new Koa();
app.use(serve(config.staticDir));
app.context.render = co.wrap(render({
varControls:["[[","]]"],// 自定义模板语法
root: config.viewDir,
autoescape: true,
cache: false, // 缓存
ext: 'html',
writeBody: false
}));
require("./controllers")(app);
app.listen(config.port, () => {
console.log("图书管理平台启动成功...");
});