mirror of https://github.com/Kylart/KawAnime.git
Restructured architecture
This commit is contained in:
parent
b04a502471
commit
c37cce3633
|
@ -4,6 +4,7 @@ module.exports = {
|
|||
'plugin:vue/essential'
|
||||
],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
ecmaVersion: 2017
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
require('./web')
|
||||
require('./main')
|
|
@ -10,7 +10,7 @@
|
|||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-image: url("static/images/index-bg.jpg");
|
||||
background-image: url("resources/index-bg.jpg");
|
||||
background-size: cover;
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
|
@ -1,154 +1,27 @@
|
|||
require('colors')
|
||||
const fs = require('fs')
|
||||
const {homedir} = require('os')
|
||||
const {homedir, userInfo} = require('os')
|
||||
const path = require('path')
|
||||
const http = require('http')
|
||||
const axios = require('axios')
|
||||
const LRU = require('lru-cache')
|
||||
const express = require('express')
|
||||
const compression = require('compression')
|
||||
const resolve = file => path.resolve(__dirname, file)
|
||||
const { createBundleRenderer } = require('vue-server-renderer')
|
||||
const redirects = require(path.join(__dirname, '/router/301.json'))
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
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(path.join(__dirname, '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(__dirname, 'public'),
|
||||
// performance
|
||||
runInNewContext: false
|
||||
}))
|
||||
}
|
||||
|
||||
let renderer
|
||||
let readyPromise
|
||||
if (!isDev) {
|
||||
const bundle = require(path.join(__dirname, 'public', 'vue-ssr-server-bundle.json'))
|
||||
const clientManifest = require(path.join(__dirname, 'public', 'vue-ssr-client-manifest.json'))
|
||||
renderer = createRenderer(bundle, {
|
||||
clientManifest
|
||||
})
|
||||
} else {
|
||||
// hot reload
|
||||
readyPromise = require(path.join(__dirname, 'webpack', 'setup-dev-server.js'))(app, (bundle, options) => {
|
||||
renderer = createRenderer(bundle, options)
|
||||
})
|
||||
}
|
||||
|
||||
const serve = (path, cache) => express.static(resolve(path), {
|
||||
maxAge: cache && !isDev ? 60 * 60 * 24 * 30 : 0
|
||||
})
|
||||
|
||||
app.use(compression({
|
||||
threshold: 0,
|
||||
filter (req, res) {
|
||||
return res.getHeader('Content-Type') === 'text/event-stream'
|
||||
? false
|
||||
: compression.filter(req, res)
|
||||
}
|
||||
}))
|
||||
app.use('/static', serve(path.join(__dirname, 'static'), true))
|
||||
app.use('/public', serve(path.join(__dirname, 'public'), true))
|
||||
|
||||
// Setup the api
|
||||
require(path.join(__dirname, '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
|
||||
})
|
||||
|
||||
const isCacheable = req => useMicroCache
|
||||
|
||||
function render ({url}, res) {
|
||||
const s = Date.now()
|
||||
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.setHeader('Server', serverInfo)
|
||||
|
||||
const handleError = (err) => {
|
||||
if (err && err.code === 404) {
|
||||
res.status(404).send('404 | Page Not Found')
|
||||
} else {
|
||||
// Render Error Page or Redirect
|
||||
res.status(500).send(`<pre>500 | Internal Server Error\n${err.stack}</pre>`)
|
||||
console.error(`error during render : ${url}`)
|
||||
console.error(err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
const cacheable = isCacheable(url)
|
||||
if (cacheable) {
|
||||
const hit = microCache.get(url)
|
||||
if (hit) {
|
||||
isDev && 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)
|
||||
}
|
||||
isDev && console.log(`> whole request: ${Date.now() - s}ms`.green)
|
||||
})
|
||||
}
|
||||
|
||||
app.get('*', !isDev ? render : (req, res) => {
|
||||
readyPromise.then(() => {
|
||||
render(req, res)
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
** Electron app
|
||||
*/
|
||||
const {BrowserWindow, dialog, Menu, Tray} = require('electron')
|
||||
const Electron = require('electron').app
|
||||
const url = require('url')
|
||||
const localConfig = require(path.join(homedir(), '.KawAnime', 'config.json')).config
|
||||
|
||||
const menuFile = require(path.join(__dirname, 'assets', 'menu.js'))
|
||||
const menuFile = require('./resources/menu.js')
|
||||
const menu = Menu.buildFromTemplate(menuFile.menu)
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
process.win = null // Current window
|
||||
let tray = null
|
||||
let _APP_URL_
|
||||
let server
|
||||
|
||||
const startServer = () => {
|
||||
const app = process.app
|
||||
|
||||
server = http.createServer(app).listen(process.env.PORT)
|
||||
_APP_URL_ = 'http://localhost:' + server.address().port
|
||||
console.log(`> KawAnime is at ${_APP_URL_}`.green)
|
||||
|
@ -165,16 +38,12 @@ const pollServer = () => {
|
|||
.on('error', pollServer)
|
||||
}
|
||||
|
||||
// Disable error dialogs by overriding
|
||||
dialog.showErrorBox = (title, content) => {
|
||||
console.log(`${title}\n${content}`)
|
||||
}
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
console.error('Uncaught exception occurred in main process.\n', err)
|
||||
})
|
||||
|
||||
const newWin = () => {
|
||||
if (!process.app) {
|
||||
setTimeout(newWin, 500)
|
||||
return
|
||||
}
|
||||
|
||||
startServer()
|
||||
|
||||
process.win = new BrowserWindow({
|
||||
|
@ -225,15 +94,29 @@ const newWin = () => {
|
|||
pollServer()
|
||||
}
|
||||
|
||||
// Disable error dialogs by overriding
|
||||
dialog.showErrorBox = (title, content) => {
|
||||
console.log(`${title}\n${content}`)
|
||||
}
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
console.error('Uncaught exception occurred in main process.\n', err)
|
||||
})
|
||||
|
||||
Electron.on('ready', () => {
|
||||
const currentSettings = Electron.getLoginItemSettings()
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
// Devtools
|
||||
if (isDev) {
|
||||
require('vue-devtools').install()
|
||||
}
|
||||
|
||||
if (localConfig.system.toTray) {
|
||||
if (process.platform === 'darwin') {
|
||||
Electron.dock.hide()
|
||||
}
|
||||
tray = new Tray(path.join(__dirname, 'static', 'images', 'tray.png'))
|
||||
tray = new Tray('./resources/tray.png')
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New window',
|
||||
|
@ -268,8 +151,8 @@ Electron.on('ready', () => {
|
|||
newWin()
|
||||
|
||||
// Let's send some data to kawanime.com/_api
|
||||
const {username} = require('os').userInfo()
|
||||
const tokenPath = path.join(require('os').homedir(), '.KawAnime', '_token')
|
||||
const {username} = userInfo()
|
||||
const tokenPath = path.join(homedir(), '.KawAnime', '_token')
|
||||
const token = fs.readFileSync(tokenPath, 'utf-8')
|
||||
axios.post('https://kawanime.com/_api', {
|
||||
id: `${username}/${token}`
|
Before Width: | Height: | Size: 512 KiB After Width: | Height: | Size: 512 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -3,7 +3,7 @@ const _ = require('lodash')
|
|||
const axios = require('axios')
|
||||
const {dir} = require('../utils')
|
||||
|
||||
const _VERSION_ = require(join(__dirname, '..', '..', 'package.json')).version
|
||||
const _VERSION_ = require(join(__dirname, '..', '..', '..', '..', 'package.json')).version
|
||||
const configPath = join(dir, 'config.json')
|
||||
const config = require(configPath)
|
||||
|
|
@ -2,7 +2,7 @@ const {join} = require('path')
|
|||
const {writeFileSync} = require('fs')
|
||||
const {dir} = require('../utils')
|
||||
|
||||
const _VERSION_ = require(join(__dirname, '..', '..', 'package.json')).version
|
||||
const _VERSION_ = require(join(__dirname, '..', '..', '..', '..', 'package.json')).version
|
||||
const configPath = join(dir, 'config.json')
|
||||
const config = require(configPath)
|
||||
|
|
@ -88,15 +88,6 @@ export default {
|
|||
mixins: [Meta, ReadMagnet, DragDrop],
|
||||
mounted () {
|
||||
this.isBrowser = !window.navigator.appVersion.includes('Electron')
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const devtools = document.createElement('script')
|
||||
devtools.src = 'http://localhost:8098'
|
||||
|
||||
document.body.appendChild(devtools)
|
||||
}
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {
|
|
@ -32,8 +32,6 @@ Object.keys(Components).forEach(key => {
|
|||
Vue.component(key, Components[key])
|
||||
})
|
||||
|
||||
if (typeof window !== 'undefined' && process.env.NODE_ENV) window.NODE_ENV = process.env.NODE_ENV
|
||||
|
||||
// Expose a factory function that creates a fresh set of store, router,
|
||||
// app instances on each call (which is called for each SSR request)
|
||||
export function createApp (ssrContext) {
|
||||
|
@ -42,7 +40,7 @@ export function createApp (ssrContext) {
|
|||
const router = createRouter()
|
||||
|
||||
// App initialization
|
||||
store.dispatch('init')
|
||||
if (typeof window !== 'undefined') store.dispatch('init')
|
||||
!['KawAnime-test', 'development'].includes(process.env.NODE_ENV) && store.dispatch('update/check')
|
||||
|
||||
// sync the router with the vuex store.
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
@ -7,7 +7,7 @@
|
|||
@import './material-icons'
|
||||
|
||||
// Vuetify
|
||||
@import '../../node_modules/vuetify/src/stylus/app'
|
||||
@import '../../../../node_modules/vuetify/src/stylus/app'
|
||||
|
||||
// Custom
|
||||
@import './electron'
|
|
@ -0,0 +1,132 @@
|
|||
require('colors')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const LRU = require('lru-cache')
|
||||
const express = require('express')
|
||||
const compression = require('compression')
|
||||
const resolve = file => path.resolve(__dirname, file)
|
||||
const { createBundleRenderer } = require('vue-server-renderer')
|
||||
const redirects = require(path.join(__dirname, '/router/301.json'))
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
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 template = fs.readFileSync(path.join(__dirname, '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(__dirname, '..', '..', 'public'),
|
||||
// performance
|
||||
runInNewContext: false
|
||||
}))
|
||||
}
|
||||
|
||||
let renderer
|
||||
let readyPromise
|
||||
|
||||
process.app = express()
|
||||
|
||||
if (!isDev) {
|
||||
const bundle = require(path.join(__dirname, '..', '..', 'public', 'vue-ssr-server-bundle.json'))
|
||||
const clientManifest = require(path.join(__dirname, '..', '..', 'public', 'vue-ssr-client-manifest.json'))
|
||||
renderer = createRenderer(bundle, {
|
||||
clientManifest
|
||||
})
|
||||
} else {
|
||||
// hot reload
|
||||
readyPromise = require(path.join(__dirname, '..', '..', 'webpack', 'setup-dev-server.js'))(process.app, (bundle, options) => {
|
||||
renderer = createRenderer(bundle, options)
|
||||
})
|
||||
}
|
||||
|
||||
const serve = (path, cache) => express.static(resolve(path), {
|
||||
maxAge: cache && !isDev ? 60 * 60 * 24 * 30 : 0
|
||||
})
|
||||
|
||||
process.app.use(compression({
|
||||
threshold: 0,
|
||||
filter (req, res) {
|
||||
return res.getHeader('Content-Type') === 'text/event-stream'
|
||||
? false
|
||||
: compression.filter(req, res)
|
||||
}
|
||||
}))
|
||||
process.app.use('/static', serve(path.join(__dirname, 'static'), true))
|
||||
process.app.use('/public', serve(path.join(__dirname, 'public'), true))
|
||||
|
||||
// Setup the api
|
||||
// TODO: Move this call to main/index.js would be great
|
||||
require(path.join(__dirname, '..', 'main', 'server'))(process.app)
|
||||
|
||||
// 301 redirect for changed routes
|
||||
Object.keys(redirects).forEach((k) => {
|
||||
process.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
|
||||
})
|
||||
|
||||
const isCacheable = req => useMicroCache
|
||||
|
||||
function render ({ url }, res) {
|
||||
const s = Date.now()
|
||||
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.setHeader('Server', serverInfo)
|
||||
|
||||
const handleError = (err) => {
|
||||
if (err && err.code === 404) {
|
||||
res.status(404).send('404 | Page Not Found')
|
||||
} else {
|
||||
// Render Error Page or Redirect
|
||||
res.status(500).send(`<pre>500 | Internal Server Error\n${err.stack}</pre>`)
|
||||
console.error(`error during render : ${url}`)
|
||||
console.error(err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
const cacheable = isCacheable(url)
|
||||
if (cacheable) {
|
||||
const hit = microCache.get(url)
|
||||
if (hit) {
|
||||
isDev && console.log('> cache hit!')
|
||||
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)
|
||||
}
|
||||
isDev && console.log(`> whole request: ${Date.now() - s}ms`)
|
||||
})
|
||||
}
|
||||
|
||||
process.app.get('*', !isDev ? render : (req, res) => {
|
||||
readyPromise.then(() => {
|
||||
render(req, res)
|
||||
})
|
||||
})
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue