11

I'm new to koa.js library and I need some help. I'm trying to make simple REST application using koa. I have a static html and javascript files I want to serve on route / and REST API accessing from /api/.

This is my project directory tree:

project
├── server
│   ├── node_modules
│   ├── package.json
│   └── src
│       ├── config
│       ├── resources
│       └── server.js
├── ui
│   ├── app
│   ├── bower.json
│   ├── bower_components
│   ├── dist
│   ├── node_modules
│   ├── package.json
│   └── test

This is my source:

var app = require('koa')();
app.use(mount('/api/places', require('../resources/places')));

// does not work
var staticKoa = require('koa')();
staticKoa.use(function *(next){
  yield next;
  app.use(require('koa-static')('../ui/app', {}));
});
app.use(mount('/', staticKoa));

// does not work
app.use(mount('/', function*() {
    app.use(require('koa-static')('../ui/app/', {}));
}));

// does not work
app.use(mount('/', function*() {
    app.use(require('koa-static')('.', {}));
}));
// GET package.json -> 404 not found

I've tried koa-static, koa-static-folder, koa-static-server libraries and neither works so I'm doing something wrong.

I've tried this and it works, but I don't have access to my REST api:

var app = require('koa')();
app.use(require('koa-static')('../ui/app/', {}));
suricactus
  • 1,210
  • 2
  • 15
  • 22

4 Answers4

24

It was a little hard for me to follow what you were doing in your example code... Here is a simple example that does everything your wanting:

'use strict';
let koa     = require('koa'),
    send    = require('koa-send'),
    router  = require('koa-router')(),
    serve   = require('koa-static');

let app = koa();
// serve files in public folder (css, js etc)
app.use(serve(__dirname + '/public'));

// rest endpoints
router.get('/api/whatever', function *(){
  this.body = 'hi from get';
});
router.post('/api/whatever', function *(){
  this.body = 'hi from post'
});

app.use(router.routes());

// this last middleware catches any request that isn't handled by
// koa-static or koa-router, ie your index.html in your example
app.use(function* index() {
  yield send(this, __dirname + '/index.html');
});

app.listen(4000);
James Moore
  • 1,881
  • 14
  • 18
  • What is the pointer `this` in the ` this.body = 'hi from get'; `? – Believe2014 Jul 01 '16 at 20:50
  • I've been wrestling with this for koa v2, maybe you can provide some insight? `app.use(async (ctx, next) => { await send(ctx, path.join(__dirname, '../', 'client/index.html')) })` I get a 404 not found error for some reason... Although with a bit of a hack I can serve the individual html file, if it isn't the folder, I'm not able to load my images, etc. – hoodsy Jul 18 '16 at 20:28
  • @hoodsy Did you ever come up with an answer? I tried app.use(async (ctx, next)... and wasn't able to get that to work. Tried various different variants but nothing seems to work. – Nurpax Aug 31 '16 at 20:47
  • @Nurpax I've got a really hacky solution from another thread I found here: http://stackoverflow.com/questions/24024566/display-a-static-html-file-with-koa-js – hoodsy Aug 31 '16 at 21:08
  • 2
    @hoodsy Through trial and error, I was able to get this working last night: `app.use(async function (ctx, next) { return send(ctx, '/index.html', { root: paths.client() }).then(() => next()) })` The key thing was to specify `{root:}`. I think the problem in my case was that for security reasons, `send` doesn't allow relative paths or paths outside of the project tree. Specifying the `root` param and then giving a filename relative to that seemed to fix the problem. I guess I expected `koa-send` to log an error/warning on the node output about this. – Nurpax Sep 01 '16 at 06:22
  • 2
    FWIW, I've run into so many problems with this koa vs koav2 thing, that I'm seriously considering porting all my stuff to express. Koa examples on the net seem to be fragmented among koa and koa v2, making it hard to get any example code working. – Nurpax Sep 01 '16 at 06:28
  • @Nurpax nice job! I'm going to have to give this a shot. A lot of the time I find myself referencing Express examples and porting them to Koa. I love the async/await style though, and would really enjoy Koa2 being widely adopted. I feel your frustrations as well. – hoodsy Sep 03 '16 at 13:50
  • what is the difference between koa-send and koa-static here? why do we need both of them? Can't we serve files from '/public' with koa-send? Thanks! – dKab Feb 13 '17 at 22:02
  • @hoodsy, I am using `app.use(async (ctx, next) => await ctx.send(\`${__dirname}/public/index.html\`))` and it works fine. – Rahman Malik May 16 '19 at 03:51
5
const root = require('path').join(__dirname, 'client', 'build');
app.use(serve(root));

app.use(async ctx => {
    await send(ctx, `/index.html`, {
        root
    });
});
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
3

From @Nurpax in the comments:

app.use(async function (ctx, next) {
  return send(ctx, '/index.html', { root: paths.client()
})
.then(() => next()) }) 

The key thing was to specify {root:<some path>}. I think the problem in my case was that for security reasons, send doesn't allow relative paths or paths outside of the project tree. Specifying the root param and then giving a filename relative to that seemed to fix the problem. I guess I expected koa-send to log an error/warning on the node output about this.

hoodsy
  • 894
  • 2
  • 11
  • 19
  • 3
    Have no idea why did you put promises in code. Just use await :) app.use(async (ctx) => { await send(ctx, '/index.html', { root: STATIC_FOLDER_PATH, }); }); – Vadim Boltach Nov 29 '16 at 22:07
0

This piece of code is working fine for me.

I'm serving auto files images and videos in koa.

const koa = require('koa');
const koaRouter = require('koa-router');
const cors = require('@koa/cors');
const koaBody = require('koa-bodyparser');
const koaSend = require('koa-send'); 
const serve = require('koa-static');
const app = new koa();
const router = new koaRouter();

router.get('/public/audios/:item', async ctx => {
    const { item } = ctx.params;
    await koaSend(ctx, { root: `./public/audios/${item}` });
});

router.get('/public/videos/:item', async ctx => {
    const { item } = ctx.params;
    await koaSend(ctx, { root: `./public/videos/${item}` });
})

router.get('/public/images/:item', async ctx => {
    const { item } = ctx.params;
    await koaSend(ctx, { root: `./public/images/${item}` });
})

app
  .use(serve('./public'))
  .use(koaBody({ jsonLimit: '100mb', formLimit: '100mb', textLimit: '100mb' }))
  .use(cors())
  .use(router.routes())
  .use(router.allowedMethods())

app.listen(3000);
M. Hamza Rajput
  • 7,810
  • 2
  • 41
  • 36