mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
ui: 优化资源加载
This commit is contained in:
1 parent
fffacdc63c
commit
c8a0d48a41
7 files changed
+111
-143
No files matched your search
@@ -1,5 +1,6 @@
|
||||
window.Hydro = {
|
||||
extraPages: [],
|
||||
preload: [],
|
||||
components: {},
|
||||
utils: {},
|
||||
node_modules: {},
|
||||
@@ -19,9 +20,28 @@ console.log(
|
||||
`,
|
||||
);
|
||||
|
||||
window.UiContext = JSON.parse(window.UiContext);
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.UiContext = JSON.parse(window.UiContext);
|
||||
|
||||
// eslint-disable-next-line
|
||||
try { __webpack_public_path__ = UiContext.cdn_prefix } catch (e) { }
|
||||
// eslint-disable-next-line
|
||||
try { __webpack_public_path__ = UiContext.cdn_prefix } catch (e) { }
|
||||
|
||||
import('./hydro');
|
||||
// Locale & langs
|
||||
const { version, payload } = JSON.parse(localStorage.getItem('hydro-constant') || '{}');
|
||||
if (version === UiContext.constantVersion) {
|
||||
eval(payload[0]); // eslint-disable-line no-eval
|
||||
payload.shift();
|
||||
window.Hydro.preload = payload;
|
||||
import('./hydro');
|
||||
} else {
|
||||
fetch(`/constant?version=${UiContext.constantVersion}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
eval(data.payload[0]); // eslint-disable-line no-eval
|
||||
localStorage.setItem('hydro-constant', JSON.stringify(data));
|
||||
data.payload.shift();
|
||||
window.Hydro.preload = data.payload;
|
||||
import('./hydro');
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
@@ -1,24 +1,82 @@
|
||||
/* eslint-disable no-return-await */
|
||||
/* eslint-disable camelcase */
|
||||
const { readdirSync, readFileSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { tmpdir } = require('os');
|
||||
const { ObjectID } = require('mongodb');
|
||||
const bus = require('hydrooj/src/service/bus');
|
||||
const { PERM } = require('hydrooj/src/model/builtin');
|
||||
const markdown = require('./backendlib/markdown');
|
||||
import crypto from 'crypto';
|
||||
import { readdir, readFile } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import * as bus from 'hydrooj/src/service/bus';
|
||||
import { Route, Handler } from 'hydrooj/src/service/server';
|
||||
import { PERM } from 'hydrooj/src/model/builtin';
|
||||
import markdown from './backendlib/markdown';
|
||||
|
||||
const {
|
||||
system, domain, user, setting, problem, contest,
|
||||
} = global.Hydro.model;
|
||||
const { Route, Handler, UiContextBase } = global.Hydro.service.server;
|
||||
|
||||
interface ConstantArgs {
|
||||
lang: string;
|
||||
domainId: string;
|
||||
}
|
||||
|
||||
const cache = {};
|
||||
|
||||
const basedir = join(tmpdir(), 'hydro', 'public');
|
||||
async function constant(args: ConstantArgs) {
|
||||
// CompileLangs
|
||||
const payload = [`window.LANGS=${JSON.stringify(setting.langs)};`];
|
||||
|
||||
// Locale
|
||||
let { lang } = args;
|
||||
if (!global.Hydro.locales[lang]) lang = system.get('server.language');
|
||||
payload[0] += `window.LOCALES=${JSON.stringify(global.Hydro.locales[lang])};`;
|
||||
|
||||
// Extra style
|
||||
let [nav_logo_dark, nav_logo_dark_2x] = system.getMany([
|
||||
'ui-default.nav_logo_dark', 'ui-default.nav_logo_dark_2x',
|
||||
]);
|
||||
const ddoc = await domain.get(args.domainId);
|
||||
nav_logo_dark = ddoc.ui?.nav_logo_dark || nav_logo_dark;
|
||||
nav_logo_dark_2x = ddoc.ui?.nav_logo_dark_2x || nav_logo_dark_2x;
|
||||
payload[0] += `\
|
||||
const e = document.createElement('style');
|
||||
e.innerHTML = \`\
|
||||
${nav_logo_dark ? `.nav__logo { background-image: url(${nav_logo_dark}) !important }` : ''}
|
||||
${nav_logo_dark_2x ? `\
|
||||
@media
|
||||
only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
||||
only screen and (min-resolution: 1.5dppx),
|
||||
only screen and (min-resolution: 144dpi) {
|
||||
.nav__logo, .header--mobile__domain {
|
||||
background-image: url(${nav_logo_dark_2x}) !important
|
||||
}
|
||||
}` : ''}\`;
|
||||
document.body.appendChild(e);`;
|
||||
|
||||
const files = await readdir(basedir);
|
||||
const pages = files
|
||||
.filter((file) => file.endsWith('.page.js'))
|
||||
.map((i) => readFile(join(basedir, i), 'utf-8'));
|
||||
payload.push(...await Promise.all(pages));
|
||||
|
||||
const c = crypto.createHash('sha1');
|
||||
c.update(JSON.stringify(payload));
|
||||
const version = c.digest('hex');
|
||||
cache[version] = { version, payload };
|
||||
return version;
|
||||
}
|
||||
|
||||
bus.on('handler/after', async (that) => {
|
||||
if (that.response.template) {
|
||||
that.UiContext.constantVersion = await constant({
|
||||
domainId: that.domainId,
|
||||
lang: that.session.viewLang || that.user.viewLang,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
class WikiHelpHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
noCheckPermView = true;
|
||||
|
||||
async get({ domainId }) {
|
||||
const LANGS = setting.langs;
|
||||
@@ -34,72 +92,15 @@ class WikiHelpHandler extends Handler {
|
||||
}
|
||||
|
||||
class WikiAboutHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
noCheckPermView = true;
|
||||
|
||||
async get() {
|
||||
this.response.template = 'about.html';
|
||||
}
|
||||
}
|
||||
|
||||
class UiConstantsHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
|
||||
async get() {
|
||||
this.response.body = `window.LANGS=${JSON.stringify(setting.langs)}`;
|
||||
this.response.type = 'text/javascript';
|
||||
this.ctx.set('nolog', '1');
|
||||
}
|
||||
}
|
||||
|
||||
class UiSettingsHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
|
||||
async get({ domainId }) {
|
||||
const [nav_logo_dark, nav_logo_dark_2x] = system.getMany([
|
||||
'ui-default.nav_logo_dark', 'ui-default.nav_logo_dark_2x',
|
||||
]);
|
||||
const ddoc = await domain.get(domainId);
|
||||
this.response.body = await this.renderHTML('extra.css', {
|
||||
nav_logo_dark,
|
||||
nav_logo_dark_2x,
|
||||
...(ddoc.ui || {}),
|
||||
});
|
||||
this.response.type = 'text/css';
|
||||
this.ctx.set('nolog', '1');
|
||||
}
|
||||
}
|
||||
|
||||
class LocaleHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
|
||||
async get({ id }) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
id = id.split('.')[0];
|
||||
// TODO use language_default setting
|
||||
if (!global.Hydro.locales[id]) id = system.get('server.language');
|
||||
this.response.body = `window.LOCALES=${JSON.stringify(global.Hydro.locales[id])}`;
|
||||
this.response.type = 'text/javascript';
|
||||
this.ctx.set('nolog', '1');
|
||||
}
|
||||
}
|
||||
|
||||
class SetThemeHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
noCheckPermView = true
|
||||
|
||||
async get({ theme }) {
|
||||
await user.setById(this.user._id, { theme });
|
||||
@@ -108,10 +109,7 @@ class SetThemeHandler extends Handler {
|
||||
}
|
||||
|
||||
class MarkdownHandler extends Handler {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.noCheckPermView = true;
|
||||
}
|
||||
noCheckPermView = true;
|
||||
|
||||
async post({ text, html = false, inline = false }) {
|
||||
this.response.body = inline
|
||||
@@ -122,6 +120,14 @@ class MarkdownHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
class UiConstantsHandler extends Handler {
|
||||
noCheckPermView = true;
|
||||
|
||||
async get({ version }) {
|
||||
this.response.body = cache[version];
|
||||
}
|
||||
}
|
||||
|
||||
class RichMediaHandler extends Handler {
|
||||
async renderUser(domainId, payload) {
|
||||
let d = payload.domainId || domainId;
|
||||
@@ -162,35 +168,11 @@ class RichMediaHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
const getHash = (i) => {
|
||||
const shasum = crypto.createHash('sha1');
|
||||
const file = readFileSync(join(tmpdir(), 'hydro', 'public', i));
|
||||
shasum.update(file);
|
||||
return shasum.digest('hex').substr(0, 10);
|
||||
};
|
||||
|
||||
const getUrl = (files) => files.map((i) => `/${i}?${getHash(i)}`);
|
||||
|
||||
bus.on('app/started', () => {
|
||||
setTimeout(() => {
|
||||
const files = readdirSync(join(tmpdir(), 'hydro', 'public'));
|
||||
const pages = files.filter((file) => file.endsWith('.page.js'));
|
||||
const themes = files.filter((file) => file.endsWith('.theme.js'));
|
||||
UiContextBase.extraPages = getUrl(pages);
|
||||
UiContextBase.themes = {};
|
||||
for (const theme of themes) {
|
||||
UiContextBase.themes[theme] = `/${theme}?${getHash(theme)}`;
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
global.Hydro.handler.ui = async () => {
|
||||
Route('wiki_help', '/wiki/help', WikiHelpHandler);
|
||||
Route('wiki_about', '/wiki/about', WikiAboutHandler);
|
||||
Route('ui_constants', '/ui-constants.js', UiConstantsHandler);
|
||||
Route('locale', '/locale/:id', LocaleHandler);
|
||||
Route('set_theme', '/set_theme/:id', SetThemeHandler);
|
||||
Route('ui_extracss', '/extra.css', UiSettingsHandler);
|
||||
Route('constant', '/constant', UiConstantsHandler);
|
||||
Route('markdown', '/markdown', MarkdownHandler);
|
||||
Route('media', '/media', RichMediaHandler);
|
||||
};
|
||||
@@ -24,25 +24,7 @@ function buildSequence(pages, type) {
|
||||
}
|
||||
|
||||
async function load() {
|
||||
if (UiContext.extraPages) {
|
||||
const tasks = [];
|
||||
const ts = new Date().getTime();
|
||||
for (const page of UiContext.extraPages) {
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
const script = document.createElement('script');
|
||||
if (page.includes('.module.')) script.type = 'module';
|
||||
script.src = page;
|
||||
head.appendChild(script);
|
||||
tasks.push(new Promise((resolve) => {
|
||||
script.onload = resolve;
|
||||
}));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
const time = new Date().getTime() - ts;
|
||||
if ((process.env.NODE_ENV !== 'production' && time > 16) || time > 256) {
|
||||
console.warn(`Extra pages loading took ${time}ms`);
|
||||
}
|
||||
}
|
||||
for (const page of window.Hydro.preload) await eval(page); // eslint-disable-line no-eval
|
||||
|
||||
const pageLoader = new PageLoader();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/ui-default",
|
||||
"version": "4.18.15",
|
||||
"version": "4.19.0",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "hydro.js",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% if udoc %}
|
||||
<span class="user-profile-link">
|
||||
{% if avatar %}
|
||||
<img class="small user-profile-avatar v-center" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
||||
<img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
||||
{% endif %}
|
||||
<a class="user-profile-name" href="{{ url('user_detail', uid=udoc._id) }}">
|
||||
{% if udoc.displayName and udoc.displayName != udoc.uname %}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/* {% if nav_logo_dark %} */
|
||||
.nav__logo {
|
||||
background-image: url({{nav_logo_dark}}) !important
|
||||
}
|
||||
/* {% endif %} */
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx), only screen and (min-resolution: 144dpi) {
|
||||
/* {% if nav_logo_dark_2x %} */
|
||||
.nav__logo, .header--mobile__domain {
|
||||
background-image: url({{nav_logo_dark_2x}}) !important
|
||||
}
|
||||
/* {% endif %} */
|
||||
}
|
||||
@@ -26,9 +26,9 @@
|
||||
{% endblock %}
|
||||
{% if not isIE(handler.request.headers['user-agent']) %}
|
||||
<script src="{{ static_url((handler.user|default({})).theme|default('default') + '.theme.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ static_url('hydro.js') }}"></script>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" media="all" href="{{ static_url((handler.user|default({})).theme|default('default') + '.theme.css') }}">
|
||||
<link rel="stylesheet" media="all" href="{{ url('ui_extracss') }}">
|
||||
<title>{{ handler.renderTitle(page_name) }}</title>
|
||||
{% if not isIE(handler.request.headers['user-agent']) %}
|
||||
<script>
|
||||
@@ -46,9 +46,6 @@
|
||||
UiContext = '{{ UiContext|json|jsesc|safe }}';
|
||||
UserContext = '{{ UserContext|json|jsesc|safe }}';
|
||||
</script>
|
||||
<script type="text/javascript" src="{{ ('/locale/{0}.js'.format(handler.translate('__id'))) }}"></script>
|
||||
<script type="text/javascript" src="/ui-constants.js"></script>
|
||||
<script type="text/javascript" src="{{ static_url('hydro.js') }}"></script>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user