KawAnime/main.js

234 lines
5.7 KiB
JavaScript
Raw Normal View History

require('colors')
const fs = require('fs')
const path = require('path')
const http = require('http')
const LRU = require('lru-cache')
const express = require('express')
const favicon = require('serve-favicon')
const compression = require('compression')
const resolve = file => path.resolve(__dirname, file)
const { createBundleRenderer } = require('vue-server-renderer')
const redirects = require('./router/301.json')
const isProd = process.env.NODE_ENV === 'production'
const useMicroCache = process.env.MICRO_CACHE !== 'false'
const serverInfo =
`express/${require('express/package.json').version} ` +
`vue-server-renderer/${require('vue-server-renderer/package.json').version}`
const app = express()
const template = fs.readFileSync(resolve('./assets/index.template.html'), 'utf-8')
function createRenderer (bundle, options) {
// https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
return createBundleRenderer(bundle, Object.assign(options, {
template,
// for component caching
cache: LRU({
max: 1000,
maxAge: 1000 * 60 * 15
}),
// this is only needed when vue-server-renderer is npm-linked
basedir: resolve('./public'),
// performance
runInNewContext: false
}))
}
2016-11-21 14:33:22 +00:00
let renderer
let readyPromise
if (isProd) {
const bundle = require('./public/vue-ssr-server-bundle.json')
const clientManifest = require('./public/vue-ssr-client-manifest.json')
renderer = createRenderer(bundle, {
clientManifest
})
} else {
// hot reload
readyPromise = require('./webpack/setup-dev-server')(app, (bundle, options) => {
renderer = createRenderer(bundle, options)
})
}
2017-04-15 14:16:14 +00:00
const serve = (path, cache) => express.static(resolve(path), {
maxAge: cache && isProd ? 60 * 60 * 24 * 30 : 0
})
app.use(compression({ threshold: 0 }))
app.use(favicon('./static/favicon.ico'))
app.use('/static', serve('./static', true))
app.use('/public', serve('./public', true))
app.use('/static/robots.txt', serve('./robots.txt'))
app.get('/sitemap.xml', (req, res) => {
res.setHeader('Content-Type', 'text/xml')
res.sendFile(resolve('./static/sitemap.xml'))
})
2017-04-15 14:16:14 +00:00
// Setup the api
require('./server')(app)
// 301 redirect for changed routes
Object.keys(redirects).forEach((k) => {
app.get(k, (req, res) => res.redirect(301, redirects[k]))
})
// 1-second microcache.
// https://www.nginx.com/blog/benefits-of-microcaching-nginx/
const microCache = LRU({
max: 100,
maxAge: 1000
})
2017-04-15 14:16:14 +00:00
const isCacheable = req => useMicroCache
2017-04-15 14:16:14 +00:00
function render ({url}, res) {
const s = Date.now()
2017-04-15 14:16:14 +00:00
res.setHeader('Content-Type', 'text/html')
res.setHeader('Server', serverInfo)
const handleError = (err) => {
if (err && err.code === 404) {
res.status(404).end('404 | Page Not Found')
} else {
// Render Error Page or Redirect
res.status(500).end('500 | Internal Server Error')
console.error(`error during render : ${url}`)
console.error(err.stack)
}
}
const cacheable = isCacheable(url)
if (cacheable) {
const hit = microCache.get(url)
if (hit) {
!isProd && console.log(`> cache hit!`.green)
return res.end(hit)
}
}
const context = {
title: 'KawAnime',
url
}
renderer.renderToString(context, (err, html) => {
if (err) {
return handleError(err)
}
res.end(html)
if (cacheable) {
microCache.set(url, html)
}
if (!isProd) {
console.log(`> whole request: ${Date.now() - s}ms`.green)
}
})
2017-04-15 14:16:14 +00:00
}
app.get('*', isProd ? render : (req, res) => {
readyPromise.then(() => {
render(req, res)
})
})
const port = process.env.PORT || 9200
const _APP_URL_ = `http://localhost:${port}`
app.listen(port, '0.0.0.0', () => {
console.log(`> server started at localhost:${port}`.green)
})
2017-04-15 14:16:14 +00:00
/*
** Electron app
*/
const {BrowserWindow, dialog, Menu} = require('electron')
const Electron = require('electron').app
2017-04-15 14:16:14 +00:00
const url = require('url')
2016-11-21 14:33:22 +00:00
const menuFile = require(path.join(__dirname, 'assets', 'menu.js'))
const menu = Menu.buildFromTemplate(menuFile.menu)
let win = null // Current window
2017-04-15 14:16:14 +00:00
const pollServer = () => {
http.get(_APP_URL_, ({statusCode}) => {
statusCode !== 200
? setTimeout(pollServer, 300)
: win.loadURL(_APP_URL_)
2017-03-17 22:16:13 +00:00
})
.on('error', pollServer)
2017-04-15 14:16:14 +00:00
}
2017-03-17 22:16:13 +00:00
// Disable error dialogs by overriding
dialog.showErrorBox = (title, content) => {
console.log(`${title}\n${content}`)
}
process.on('uncaughtException', (err) => {
2017-07-19 07:50:10 +00:00
console.error('Uncaught exception occurred in main process.\n' + err.message)
})
2017-04-15 14:16:14 +00:00
const newWin = () => {
win = new BrowserWindow({
width: 1200,
height: 800,
titleBarStyle: 'hidden',
frame: process.platform === 'darwin',
2017-04-15 14:16:14 +00:00
show: false
})
win.once('ready-to-show', () => {
win.show()
2016-11-21 14:33:22 +00:00
})
2017-05-08 13:18:10 +00:00
win.on('closed', () => {
win = null
})
2016-11-21 14:33:22 +00:00
win.webContents.on('crashed', (event) => {
console.error('Main window crashed')
console.error('Event is ' + event)
})
win.on('unresponsive', () => {
console.warn('Main window is unresponsive...')
})
win.on('session-end', () => {
console.info('Session logged off.')
})
if (isProd) {
return win.loadURL(_APP_URL_)
} else {
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
2017-04-15 14:16:14 +00:00
pollServer()
2016-11-21 14:33:22 +00:00
}
Electron.on('ready', () => {
2017-04-26 17:58:21 +00:00
Menu.setApplicationMenu(menu)
2017-04-15 14:16:14 +00:00
newWin()
2017-04-27 19:05:55 +00:00
process.win = win
process.appURL = _APP_URL_
2017-03-11 17:50:14 +00:00
})
2016-11-21 14:33:22 +00:00
// Quit when all windows are closed.
Electron.on('window-all-closed', function () {
2016-11-21 14:33:22 +00:00
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
2017-05-08 13:38:26 +00:00
if (process.platform !== 'darwin') {
2016-11-21 14:33:22 +00:00
app.quit()
}
})
Electron.on('activate', () => win === null && newWin())