egg项目构建

我是使用脚手架搭建,内容参照egg官网,只是把我自己搭建的过程记录下来

egg

创建脚手架
先创建文件夹、进入文件夹

mkdir egg-example && cd egg-example

进行脚手架的搭建

npm init egg --type=simple

安装依赖

npm i

启动看看

npm run dev

文件结构
创建出来的目录

  |-controller\ 用于解析用户的输入,处理后返回相应的结果
  |

app --|-public\ 用于放置静态资源
|
|-router.js 用于配置 URL 路由规则
controller
这里的文件与router相对应,也是网页输出的地方,这样就有一个简单的项目流程了

大概的流程是

写路径 => 在controller里创建对应的js => js输出内容到网页

刚刚创建的项目,内容非常的少,现在我们一点点补充内容

ejs 模板输出
我们现在的输出手段太简陋了,现在用我们最喜欢的html来输出,这里我选择的是ejs模板,这也是egg支持的

这里参考初始化 egg+ejs 项目

安装 egg-view-ejs

npm install egg-view --save

npm install egg-view-ejs --save

配置 egg-view-ejs
进入 config/plugin.js,将文件的内容清空,修改成下面这样

// 支持ejs

exports.ejs = {
  enable: true,
  package: 'egg-view-ejs',
};

这里我发现,有严格模式,于是我想把严格模式关掉,egg脚手架自带了一些规则,在.eslintrc文件里,我习惯用我这套规则,如果要添加的话,可以参考.eslintrc.js相关配置

{
  "parserOptions": {
      "ecmaVersion": 2017
  },
  "env": {
      "es6": true,
  },
}

现在继续ejs的修改,在 config/config.default.js下添加配置

// 支持ejs

  config.view = {
    defaultViewEngine: 'ejs',
    mapping: {
      '.ejs': 'ejs',
    },
  };

写ejs
开始写之前,先在app文件夹下创建view文件夹

新建home.ejs

ejs的书写方式,参考ejs官网

渲染的方法,在我们的输出入口controller里设置,egg内置了ejs的渲染方式,在ctx对象里的render

async index() {
const ctx = this.ctx;
await ctx.render(‘home.ejs’, { data:要传的参数 });
}
render的第二个参数,是对象,可以将一些数据放到ejs里用

这里默认是在view文件夹下,如果想链接到view\pc\index.ejs,就是’pc\index.ejs’

现在的流程变成

设置url => 在controller里设置出口口 => 写ejs => 在出口将ejs输出

ejs扩展(helper)
helper,是创建在app\extend\helper.js 里的js,在这里定义的函数,可以直接在ejs里引用

比如我在helper.js里定义一个函数

module.exports = {
  stringAdd(str) {
    return str + " + helper";
  }
}

这时,ejs里可以这样写

<%= helper.stringAdd('测试') %>

页面展示为

测试 + helper
知识扩展:规范
controller只是设置数据和输出口的地方,egg支持我们将代码规范起来

context(逻辑)
egg支持我们将逻辑区分出来,我们可以在app\extend里创建context.js,这里的函数,会被合并到egg内置的ctx对象里

service(服务)
egg支持我们将网络服务区分出来,我们可以在app\service里创建js,js里的函数,会被合并到egg内置的ctx对象的service对象里

例子
我们在context.js里写函数

app\extend\context.js

module.exports = {
  cs() {
    return '测试';
  }
};

我们在service\里写函数

app\service\home.js

const Server = require('egg').Service;

class HomeServer extends Server {
  /**
   * 测试用
   * @param {String}} str
   */

  stingAdd(str) {
    return str + '后手添加';
  }

}

module.exports = HomeServer;

然后,我们在controller里使用这些逻辑

controller\home.js

const Controller = require('egg').Controller;

class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    const css = ctx.cs();
    const assignData = {
      title: 'egg',
      cs: css,
    };
    assignData.csTitle = this.service.home.stingAdd('?')
    await ctx.render('home.ejs', assignData);
  }
}

module.exports = HomeController;

ejs上的代码

<%= helper.stringAdd(cs) %>

<%= csTitle %>

最后,页面输出的是

测试 + helper
?后手添加

js的使用
差不多到了用js的时候了,egg有专门的静态文件存放地,我们把js等静态文件建在public文件夹下

egg内置了自动继承静态资源配置

使用方法
如下所示静态资源,我们在html里可以通过"/public/index.js"进行访问

app/public
|–index.js
egg的静态资源管理还有一些默认配置。参考资料

打包
只是简单的引用js肯定不行,我们要对js进行打包处理。打包js、多环境打包js

获取hash后缀的js
打包好的hash后缀js如何使用?

创建引用路径存放地
为了能正确的引用到对应的js,我们要在打包js的时候,把js的引用路径保存下来

我们在public下,建个scripts文件夹,放置js的引用路径

app/bublic
|-- script
编写插件
插件能让我们在webpack运行的过程中插入一些程序,这次我们要在打包完js的时候生成对应的引用路径。插件是什么、编写插件

首先,先创建插件js,这次我在webpack文件夹下创建一个插件plugins文件夹,放置一些插件js

app/public
      |-- webpack
            |-- plugins
                  |-- jsScriptsPlugins.js
jsScriptsPlugins.js就是我们创建的插件js,内容如下

const fs = require('fs');
const path = require('path');

var JsScriptsPlugins = function(){

}

JsScriptsPlugins.prototype.apply = function(compiler){
  compiler.plugin("emit", function(compilation, done){ // emit 事件
    for(let fileName in compilation.assets){ // 获取输出的静态资源并遍历
      var name = fileName.split('.')[0];  // 获取js前缀
      var template = `module.exports = { // 设置内容模板
        'path': ['public/release/${fileName}']}` 
      var filePath = path.join(__dirname, "../../scripts/") + name + ".js";// 引入路径的存放js
      fs.writeFile(filePath, template, 'utf8', function(error){ // 写入文件
        if(error){
          console.log(error)
        }
        console.log(`\x1B[36m写入${filePath}成功\x1B[0m`);
        console.log(`\x1B[36m内容为${template}\x1B[0m`);
        console.log('\n');
      });
    }
    done();
  });
}


module.exports = JsScriptsPlugins;

Webpack 会调用 BasicPlugin 实例的 apply 方法给插件实例传入 compiler 对象。compiler 钩子

在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,这次我们用的是emit事件

emit 事件
生成资源到 output 目录之前。

compilation.assets
存放当前所有即将输出的资源

fs.writeFile()
文件写入:fs.writeFile(‘文件路径’,‘要写入的内容’,[‘编码’],‘回调函数’);

我们在emit事件中,获取到了即将打包的js资源,因为是对象类型,我们用for…in进行遍历操作。

遍历的操作流程大概为

获取js名 => 获取js前缀 => 设置内容模板 => 设置对应的存放路径js => 将设置好的内容写入文件里

模板内容是根据打包后,输出的地址来设置的

【注】这里有个需要注意的,emit事件的第二个参数done,这是个通知函数,处理完毕后执行done,以通知 Webpack,如果不执行done,运行流程将会一直卡在这不往下执行

引用插件
插件设置好了,现在开始引人插件,回到webpack文件里来

// 引入js

const jsScriptsPlugin = require('./plugins/jsScriptsPlugins');

module.exports = {
  entry: entry,
  output: {
    filename: "[name].[chunkhash].js",
    path: outputPath,
    publicPath: path.resolve(__dirname, "../release")
  },
  plugins: [
    new jsScriptsPlugin(),  // 加入插件
  ]
}

这样插件就生效了

不同环境引用js
我们现在打包了两种环境的js,如何区分引用才好呢?

我是简单的在context.js里添加函数来获取

module.exports = {
  getProdScript(name){
    return require('../public/scripts/' + name)['path'];
  },
  getDevScript(name){
    return 'public/dist/' + name + '.js';
  }
}

分别返回不同环境,相同js的路径,然后我们在controller里,将路径作为数据传入到ejs,ejs再进行引入

// app/public/controller/home.js
const Controller = require('egg').Controller;

class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    await ctx.render('home.ejs',{script: ctx.getDevScript('a')});
  }
}

module.exports = HomeController;

// app/public/view/home.ejs

<script src="<%= script %>"></script>

可配置打包文件
我们在之前的打包入口配置中,都是已写死的方法来做的,现在我们要把打包入口配置,进行优化

配置文件
先建一个文件夹config,用来放配置文件,文件配置按下面的来

app/public/webpack/config/a.js

const path = require('path');

module.exports = {
  on: 1,  // 是否需要打包
  scriptRules: [
    {
      enable: true, // 为了支持配置多个文件,这里再细化处理了,判断这个js是否需要打包
      name: 'a',  // 打包入口配置键
      entry: path.resolve(__dirname, '../../a.js')  // 打包入口配置值
    },
  ]
}

生成入口配置
再在webpack下创建webpack.settings.js文件

app/public/webpack/webpack.settings.js

老样子,先上代码

const fs = require('fs');
const path = require('path');
const confPath = path.join(__dirname, "./config");

function getEnrty (confPath) {
  if(fs.existsSync(confPath)){  // 判断路劲是否存在
    var files = fs.readdirSync(confPath); // 获取路径下的所有文件,返回数组
    var fileArray = [];
    files.forEach(file =>{
      var filePath = path.join(confPath, file); // 配置文件的路径
      var stat = fs.statSync(filePath); // 获取文件信息
      var isFile = stat.isFile(); // 判断是否是文件
      if(isFile){ //  如果是
        fileArray.push(path.join(confPath, file));  // 存入数组
      }
    })
// 遍历文件数组,提取文件的内容,判断on是否为1,将需要打包的内容重新放入一个数组
var configModules = fileArray.map(require).filter(item => item.on === 1);
var entry = {};
    // 遍历需要打包的文件配置,再细化,判断scriptRules是否需要打包,最后将需要打包的文件配置按入口要求,设置到对象里
    configModules.forEach(config => {
      config['scriptRules'].forEach(scriptRules => {
        if(scriptRules.enable){
          entry[scriptRules['name']] = scriptRules['entry']
        }
      })
    });
    return entry; // 返回入口配置
  }else{
    return {};
  }
}

entry = getEnrty(confPath);

module.exports = entry;

先讲下这个文件作用,这个js会把config下的配置文件内容全部读取,然后根据配置,分辨哪些js需要打包,哪些不需要,最后返回一个对象,用于打包入口

引用入口配置
引用这个配置就很简单了

在webpack打包js里,直接引用

const entry = require(’./webpack.settings’); // 引入配置对象

entry: entry, // 主文件入口,加上即可用
这个方法,开发环境和生成环境打包都可以用,十分方便,统一管理,统一配置

app.js,服务启动时执行
在项目根目录下创建app.js文件,暴露一个函数,项目启动时会执行这个函数

// app.js
module.exports = function () {
  console.log("服务启动")
}

这样,每次我们项目启动的时候,都会看到"服务启动"

作者:暮光丶
链接:https://www.jianshu.com/p/a2c7e5197b0a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(node)