21

What I want to do is serve the index.html file when the index route (i.e. localhost:3000) is called.

I use koa-router for routing, so my route looks like this:

app.all("/", function * (next){
    //Send the file here
});

I tried to use koa-static like this:

var serve = require('koa-static');
 app.all("/", function * (next){
        serve("index.html");
    });

But that didn't work. Then I tried to use co-views (I put the html file in the public directory now):

var views = require("co-views");
var render = views("public");
app.all("/", function * (next){
    this.status = 200;
    this.body = yield render("index.html");
});

But that didn't work.

So can anyone tell me what I have to do?

Hugo Dozois
  • 8,147
  • 12
  • 54
  • 58
tomet
  • 2,416
  • 6
  • 30
  • 45

3 Answers3

20

Well there are a few ways to do it, here's two of them.

Templating engine

The simplest way is probably to use a templating engine like swig or jade to serve the file.

To install it do :

npm install -s swig

In order to do it with co-views, just do

var views = require("co-views");
var render = views("public", { map: { html: 'swig' });
app.all("/", function * (next){
  this.body = yield render("index");
}); 

Plain file system

Or if you don't want to use a templating engine you can use the plain Node File System library.

In order to be able to use it with yield, you have to wrap the function in a promise.

var fs = require('fs');

var readFileThunk = function(src) {
  return new Promise(function (resolve, reject) {
    fs.readFile(src, {'encoding': 'utf8'}, function (err, data) {
      if(err) return reject(err);
      resolve(data);
    });
  });
}

app.use(router.get('/', function *(){
  this.body = yield readFileThunk(__dirname + '/public/htmlfilename.html');
}));

Also, note that if you use koa-static, and you put index.html in your public folder (the folder you link to koa-static), it's going to serve index.html by default on the root url without any code. This is a convention.

Hugo Dozois
  • 8,147
  • 12
  • 54
  • 58
  • @Hugo Dozois, how to serve a different file than index.html? i have used koa-static with the file name, app.html, as a route middleware for a specific route, but i still get the file named index.html. – sçuçu Jan 05 '16 at 17:28
  • 1
    So https://github.com/visionmedia/jade now redirects to https://github.com/pugjs/pug which at least is still a template engine.*EDIT* Jade has rebranded as Pug, so everything makes sense now. – dckuehn Sep 13 '16 at 19:46
  • Very nice answer, but it's pretty stupid that it can't be done using koa-static directly - I mean it must have some similar code inside already. – Renra Nov 22 '16 at 14:56
17

Passing file stream to koa body

This is very similar to the solution above with plain file system, but it makes use of the koa ability to pass readable streams as the response body. So the only thing we need to do is to open a readable stream to a file and pass it to koa context body. Before that give a hint to koa that this is html type response.

import { createReadStream } from 'fs';

public async handle(ctx, next) {
    ctx.type = 'html';
    ctx.body = createReadStream('index.html');
}
matiangul
  • 369
  • 2
  • 8
  • Usually it's better to explain a solution instead of just posting some rows of anonymous code. You can read [How do I write a good answer](https://stackoverflow.com/help/how-to-answer), and also [Explaining entirely code-based answers](https://meta.stackexchange.com/questions/114762/explaining-entirely-%E2%80%8C%E2%80%8Bcode-based-answers). – Massimiliano Kraus Aug 18 '17 at 08:09
  • 1
    Edited @MassimilianoKraus – matiangul Aug 22 '17 at 14:59
  • 1
    What's the public keyword doing? – mLuby Dec 22 '17 at 17:57
  • 3
    `public` method modifier comes from TypeScript class definition. This is example copied from my TypeScript codebase. @mLuby – matiangul Dec 23 '17 at 19:50
  • nice, exactly what I needed – inf3rno Apr 12 '20 at 13:01
3

What about this, using koa-static

app.all("/", async(ctx, next) => 
  serve(`${__dirname}/public`)(
    Object.assign(ctx, { path: 'index.html' }), 
    next)
  );
Gabroe
  • 37
  • 1
  • 4