步骤

  1. 打开命令行工具敲命令 ``` cd Desktop mkdir webframework cd webframework npm init -y
  1. 2. 在编辑器中找到 `package.json` 文件在里面填一些自己项目的基本信息
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-cb9feac1a04b07b3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 3. 在项目中新建项目所需要的文件夹以及文件
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-0dedd70f0dc1abcb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  5. 结构如下:<br />
  6. build<br />
  7. config(配置使用的文件夹)<br />
  8. docs<br />
  9. src -> nodeuii -> app.js(项目启动文件)<br />
  10. src -> webapp(前台项目使用的文件夹)<br />
  11. test<br />
  12. README.md
  13. 4. 接下来在命令行中给项目安装 `koa` 的包

//koa 是项目上线时所必须用到的所以用 —save npm install koa —save

  1. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-6a5c3c221682cc8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  2. 5. 之后就可以在项目中的启动文件 `app.js` 中引用 `koa`

import Koa from ‘koa’;

  1. 6. 因为在项目中还会用到 `gulp` 所以需要在项目中新建一个 `gulpfile.js` 文件并进行配置
  2. > 下面的使用 gulp 编译 node 代码的具体原因:<br />
  3. 使用 webpack 编译 node 时会生成一堆恶心的代码 实际上就是他会自己写一个 function require(){} 在浏览器端实现这个方法,但是实际上 node 自己已经支持 require 所以这个显得有些多此一举了;<br />
  4. 使用 gulp 完成这个编译工作已经是足够做到了,而且它即轻又快 所以这里推荐使用 gulp 来编译 node 的代码<br />
  5. 这里提一下:使用 webpack 可以实现 "不生成恶心的代码" 的功能,但是整个方法配置起来过于繁杂了
  6. 7. 在命令行中安装 `gulp`

//gulp 是项目上线时不需要用到的所以用 —save-dev npm install gulp —save-dev

  1. 8. `gulpfile.js` 文件中进行配置

const gulp = require(‘gulp’); const babel = require(‘gulp-babel’);//引入 gulp 的编译工具 https://www.npmjs.com/package/gulp-babel const watch = require(‘gulp-watch’);//引入 gulp 的监听工具 https://www.npmjs.com/package/gulp-watch

//开发阶段的 task gulp.task(‘builddev’, () => gulp.src(‘./src/nodeuii/*/.js’)//需要编译的文件 .pipe(babel({ presets: [‘env’] })) .pipe(gulp.dest(‘./build/‘)));//文件编译后储存的目录

//上线版本的 task gulp.task(‘buildprod’, () => {

});

//判断进程中使用的是 dev 还是 prod 返回一个 boolean 值 const _flag = (process.env.NODE_ENV == ‘procuction’);

//这个执行一个默认就会执行的 task gulp.task(‘default’, [_flag ? ‘buildprod’ : ‘builddev’])

  1. - 在命令行中安装 [gulp-babel](https://www.npmjs.com/package/gulp-babel) 这里需要注意的是需要一起安装 babel 附加的包

npm install —save-dev gulp-babel babel-core babel-preset-env

  1. 9. 因为上面配置时使用了 `babel` 所以需要在项目中新建一个 `.babelrc` 的配置文件,需要注意的时,即使这个文件不配置东西也是要写一个 `{}`
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-d303ea92e55b6c1c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 10. 也可以不使用上面的那个全局公用的 `.babelrc` 文件,实际上这个文件是给 `webpack` 使用的
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-8610f4a932543a52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. 11. 下面的预先设置也不要了,改成我们自己需要的插件
  6. > [babel-plugin-transform-es2015-modules-commonjs](https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs)
  7. - 在命令行中安装

npm install —save-dev babel-plugin-transform-es2015-modules-commonjs

  1. > 在配置中引用<br />
  2. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-22961631a715d228.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 12. 实际上上面的配置是上线环境用到的,开发环境和这个是一样的只是说需要多配置一个 `gulp-watch` 进行实时的编译,这里可以直接将上面写好的配置复制到上线环境中
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-7a23bb75f8fa9676.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. 13. 因为开发环境需要多配置一个 `gulp-watch` ,所以这个再回到 `开发环境` 里来进行设置
  6. - 在命令行中安装 [gulp-watch](https://www.npmjs.com/package/gulp-watch)

npm install —save-dev gulp-watch

  1. - 修改开发环境的配置

//开发阶段的 task gulp.task(‘builddev’, () => { return watch(‘./src/nodeuii//*.js’, { ignoreInitial: false }, () => { gulp.src(‘./src/nodeuii//*.js’)//需要编译的文件 .pipe(babel({ babelrc: false,//这个可以不使用全局的 .babelrc 配置文件 然后在下面自定义需要的配置 ‘plugins’: [ ‘transform-es2015-modules-commonjs’//https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs ] })) .pipe(gulp.dest(‘./build/‘))//文件编译后储存的目录 }) } );

  1. 14. 之后编辑 package.json 文件,在里面增加开发和生产环境的命令
  2. - 这里需要装一个包 [cross-env](https://www.npmjs.com/package/cross-env) 它可以配置系统的环境变量,因为每个系统的环境变量是不一样的所以需要我们手动地去设置这个环境变量

npm install —save cross-env

  1. - 因为之前在 `gulpfile.js` 文件中设置使用的变量名为 `NODE_ENV` 所以这里在这里设置时也应该是一致的,这是我们这个顺序有点颠倒了而已
  2. - 具体代码的写法:
  3. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-71196a43ac635401.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

//前面的是 npm run 执行时使用的命令名称,后面的首先是设置相应的全局变量 后面的 gulp 是执行编译命令 “build:dev”: “cross-env NODE_ENV=development gulp”, “build:prod”: “cross-env NODE_ENV=procuction gulp”

  1. 15. 接下来在命令行中执行一下上面的命令测试是否成功

npm run build:dev

  1. - 命令行中显示如下即表示运行正常了
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-c22f6a7fa52a35bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. - 再到项目中找到 build -> app.js 文件可以看到已经编译成功了
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-37233f44e0008459.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. - 修改 nodeuii -> app.js 文件之后再去看 build -> app.js 文件可以看到已经可以实时编译了
  6. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-3f9c3530e9bd53c0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  7. 16. 上面使用的是开发环境的命令,也可以使用生产环境的命令进行编译,这样编译出来的东西就是可以直接上线使用的,也不会走 `watch` 那个步骤了

npm run build:prod

  1. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-2414f0f98a6c95d1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  2. 17. 接下来在项目中引入 [gulp-rollup](https://www.npmjs.com/package/gulp-rollup) 包,这个包主要是为了清理掉像下面这样的情况时多余的无用代码的
  3. - nodeuii -> app.js
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-c463ed804df1083a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. - 这里在命令行中执行 `npm run build:prod` 命令会发现编译后的代码中上面的那段开发环境中执行的代码片段其实是多余无用的,而且它也会走一遍这个代码片段的逻辑增加代码的复杂程度,所以这里选择 `gulp-rollup` 进行代码的清洗
  6. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-4a9bcd152cdadc25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  7. - 安装包

npm install —save-dev gulp-rollup

  1. - 这个包主要是为了清洗上线环境多余的代码的,所以只需要给上线环境配置即可,编辑 `gulpfile.js` 文件

const rollup = require(‘gulp-rollup’);

.pipe(rollup({ input: ‘./src/nodeuii/app.js’,//需要清洗的文件 format:’cjs’ }))

  1. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-8c3d712c546c1048.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  2. 18. 之后再在控制台进行生产环境的编译

npm run build:prod

  1. - 这个时候再次打开 build -> app.js 文件会发现并没有清除成功,下面的无用的代码片段还在
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-6d0573990060baba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. - 这个时候试一下直接将 nodeuii -> app.js 中里面 `if` 判断的值直接改为 `false` 会发现这样是有效的
  4. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-24ce40cde6529692.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. - 上面的测试就证明是在清洗过程中它并不能识别 ENV 的结果(webpack 是可以识别的),这里就需要再引用一个包 [rollup-plugin-replace](https://www.npmjs.com/package/rollup-plugin-replace)
  6. - 安装

npm install —save-dev rollup-plugin-replace

  1. - 之后编辑 `gulpfile.js` 文件

const replace = require(‘rollup-plugin-replace’);

‘plugins’:[ replace({//这里是将 env 进程不是 procuction 便会自动不执行了 ‘process.env.NODE_ENV’: JSON.stringify(‘procuction’) }) ]

  1. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-c7e5900b1147740f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  2. 19. 之后再在命令行中执行编译命令

npm run build:prod

  1. - 再去查看 build -> app.js 文件,可以看到已经将下面的无用代码片段清洗掉了
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-5baa62163d2a811f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 20. 这里在项目中新建一个文件 nodeuii -> test.js ,之后在<br />
  4. app.js 中引入该文件并在命令行中进行编译
  5. - nodeuii -> test.js
  6. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-64d4d537429acfad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  7. - nodeuii -> app.js
  8. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-61f1f8cf1b0bd79b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

npm run build:prod

  1. - 得到的结果可以得出以下结论编译的处理机制
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-55048f04c17bbdbd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  3. gulp 处理设置的某个或者是多个文件,处理之后还是生成相应的目录<br />
  4. webpack 处理设置的某个或者是多个文件,处理之后将文件按照 output 中的配置进行生成<br />
  5. rollup 处理 input 的参数文件且文件只能是一个
  6. 21. 再回去看下 build -> app.js 编译后的结果可以看到这里实际上是有问题的
  7. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-0ebb68f60d3394b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  8. - 问题:这里将变量都重复的引用了两遍,造成这个问题的原因是在执行编译命令时 nodeuii -> app.js 这个文件被 babel rollup 重复的编译了两次
  9. - 解决方法:在 babel 编译时将 nodeuii -> app.js 这个文件排除掉即可
  10. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-21b49bad9223a1c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  11. - 再次在命令行中编译 `npm run build:prod` ,查看 build -> app.js 的编译结果,完美了!
  12. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-917a6c4ab9f42e84.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  13. 22. 需要注意的是这里又有了新的问题 `build:prod` 编译之后并没有把 `test.js` 文件也编译过来,它相当于是在 rollup 清洗时将其他的文件都给去掉了,导致最终只有 `app.js` 这一个文件生成了出来
  14. - 解决方法:将之前的整个的清洗的工作流分成两个 task 任务进行清洗即可

//清洗 nodeuii 目录中其他的 js 文件 gulp.task(‘buildother’, () => { gulp.src(‘./src/nodeuii//*.js’)//需要编译的文件 .pipe(babel({ babelrc: false,//这个可以不使用全局的 .babelrc 配置文件 然后在下面自定义需要的配置 ‘ignore’: [‘./src/nodeuii/app.js’],//排除启动文件使其只在下面的 rollup 中进行编译避免重复编译所产生的问题 ‘plugins’: [ ‘transform-es2015-modules-commonjs’//https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs ] })) .pipe(gulp.dest(‘./build/‘))//文件编译后储存的目录 }); //单独清洗 nodeuii 目录中的 app.js 文件 gulp.task(‘buildapp’, () => gulp.src(‘./src/nodeuii//*.js’)//需要编译的文件 .pipe(rollup({ input: ‘./src/nodeuii/app.js’,//需要清洗的文件 format: ‘cjs’, ‘plugins’: [ replace({//这里是将 env 进程不是 procuction 便会自动不执行了 ‘process.env.NODE_ENV’: JSON.stringify(‘procuction’) }) ] })) .pipe(gulp.dest(‘./build/‘))//文件编译后储存的目录 ); //将上面的两个清洗任务合并成一个任务 gulp.task(‘buildprod’,[‘buildother’,’buildapp’]);

  1. - 之后在命令行中执行编译 `npm run build:prod` 即可,为了看到效果可以将之前编译的这两个文件删掉,这样编译之后便可以清晰的看到效果了
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-bc160344a5a94f7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 23. 上面的步骤还需要优化:实际上不需要合并任务只需要在判断 Node 的进程名称是否为 `procuction` (生产环境) 时将相应的任务加上即可,不然的话相当于又多了合并的这个步骤,这里需要定义一个变量进行传递因为直接写是不识别的,把之前定义的 `flag` 删掉这样就完美了

//先将之前的 buildprod 合并的任务和 _flag 变量删掉已经不需要了

//创建一个接收任务字符串的变量 let _task = [‘builddev’]; if(process.env.NODE_ENV == ‘procuction’){//判断进程中使用的是 dev 还是 prod 执行相应的任务 _task = [‘buildother’,’buildapp’]; }

//这个执行一个默认就会执行的 task gulp.task(‘default’, _task);

  1. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-b5dd2b59ffb8a8ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  2. 24. 延伸插件 [gulp-better-rollup](https://www.npmjs.com/package/gulp-better-rollup)
  3. > 这款插件可以替代 babel 直接对 node 的代码进行编译,而且出来的东西比 babel 还要干净<br />
  4. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-febbe12aa3352fad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  5. - 唯一不足的地方就是它不能像之前的 `rollup` 那样进行代码的清洗
  6. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-24383a06b64d5126.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  7. - 在上面的代码基础上调试进行的修改部分
  8. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-782f0a7db28459b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  9. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-7a4e9f5cc8d40b86.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  10. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-d90976179a8c5783.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  11. 25. 还原恢复
  12. - 编译后的 build -> app.js & test.js
  13. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-47f77a8943515473.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  14. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-e1e1fdbbcf911f4a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  15. 26.之后完善整个的项目结构(这里参照的是 Yii 脚手架的架构)<br />
  16. nodeuii -> assets<br />
  17. nodeuii -> config -> local.js 开发环境端口配置文件<br />
  18. nodeuii -> config -> main.js 主要的端口配置文件(在里面做进程判断)<br />
  19. nodeuii -> controllers -> IndexController.js<br />
  20. nodeuii -> controllers -> InitController.js 初始化路由<br />
  21. nodeuii -> models
  22. 27. 编辑文件
  23. - nodeuii -> config -> local.js

//开发环境的配置 const localConfig = { ‘port’:8081//定义端口号 } export default localConfig;

  1. - nodeuii -> config -> main.js

//上线环境的配置 import _ from ‘lodash’;//引入 lodash (https://www.npmjs.com/package/lodash) lodash 中文网 import local from ‘./local’;//引入本地开发环境的配置

const server = { ‘port’:80//设置上线版本的端口号 一般都是 80 }; let config = { ‘env’:process.env.NODEENV }; if(config.env == ‘procuction’){//判断如果进程是否是上线状态 config = .extend(server); }else{ config = _.extend(local); } export default config;

  1. - nodeuii -> app.js

import Koa from ‘koa’;//引入 koa 面向node.js的表现型HTTP中间件框架,使Web应用程序和API更加令人愉快地编写 (https://www.npmjs.com/package/koa) import router from ‘koa-simple-router’;//引入 koa-simple-router 简单而快速的路由器(https://www.npmjs.com/package/koa-simple-router) import render from ‘koa-swig’;//引入 koa-swig 视图渲染 (https://www.npmjs.com/package/koa-swig) import serve from ‘koa-static’;//引入 koa-static Koa静态文件服务中间件 (https://www.npmjs.com/package/koa-static) import config from ‘./config/main’;//引入 端口 配置文件 import InitController from ‘./controllers/InitController’;//引入 InitController const app = new Koa();//实例化 app.listen(config.port,()=>{ console.log(‘Server is start’); });

  1. - 之后在命令行中将上面代码所需要引入项目的包安装一遍

npm install koa-simple-router koa-swig koa-static —save npm install lodash —save

  1. - 还需要全局安装一个热启的包 使某个文件可以进行实时更新,如果之前装过就直接使用下面的启动命令即可

//全局安装 npm install -g supervisor //启动某个文件命令 supervisor ./build/app.js

  1. - 这个时候在命令行中执行命令,就可以实现正常的编译与启动服务了

//编译 npm run build:dev //或者 npm run build:prod

//启动文件 supervisor ./build/app.js

  1. - 控制台显示已经成功了
  2. > ![image.png](http://upload-images.jianshu.io/upload_images/9064013-c2d7078236e44e15.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  3. 28. 接着写 router 路由 编辑 `controllers` 目录下的文件
  4. > 语法参照:[https://www.npmjs.com/package/koa-simple-router](https://www.npmjs.com/package/koa-simple-router)
  5. - InitController.js

//初始化路由 import IndexController from ‘./IndexController’;

//koa-simple-router 示例代码片段 https://www.npmjs.com/package/koa-simple-router // app.use(router( => { // .get(‘/‘, (ctx, next) => { // ctx.body = ‘hello’ // }) // _.post(‘/name/:id’, (ctx, next) => { // // … // }) // })

const IndexControllerIns = new IndexController(); const InitController = { getAllrouters(app, router) { app.use(router(=>{ .get(‘/‘,IndexControllerIns.index()) _.get(‘/Index.html’,IndexControllerIns.index()) })); } }; export default InitController;

  1. - IndexController.js

import IndexModel from ‘../models/IndexModel’; class IndexController{ constructor(){ } index(){ return async(ctx,next) =>{ ctx.body = ‘123’; } } } export default IndexController;

  1. - 再在 `app.js` 文件中初始化所有路由

InitController.getAllrouters(app,router);//初始化所有路由

  1. - 之后再在命令行中编译一下,再启动 app.js 文件

npm run build:dev supervisor ./build/app.js

```

  • 访问浏览器相应的 8081 端口 输入路由 / 和 ‘/Index.html’

image.png
image.png

  • 当然了上面的只是最基础简单的路由搭建方法,后面还需要进一步的完善