mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 01:38:19 +08:00
ui: optimize bundle
This commit is contained in:
1 parent
9c02ed4dd8
commit
5ae8258b8a
28 files changed
+57
-179
No files matched your search
@@ -1,15 +1,15 @@
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable guard-for-in */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import _ from 'lodash';
|
||||
import gulp from 'gulp';
|
||||
import log from 'fancy-log';
|
||||
import chalk from 'chalk';
|
||||
import svgmin from 'gulp-svgmin';
|
||||
import vinylBuffer from 'vinyl-buffer';
|
||||
import log from 'fancy-log';
|
||||
import gulp from 'gulp';
|
||||
import iconfont from 'gulp-iconfont';
|
||||
import plumber from 'gulp-plumber';
|
||||
import gulpif from 'gulp-if';
|
||||
import plumber from 'gulp-plumber';
|
||||
import svgmin from 'gulp-svgmin';
|
||||
import _ from 'lodash';
|
||||
import vinylBuffer from 'vinyl-buffer';
|
||||
import nunjucks from '../plugins/gulpNunjucks';
|
||||
import vjTouch from '../plugins/gulpTouch';
|
||||
|
||||
|
||||
@@ -217,7 +217,6 @@ export default function (env: { production?: boolean, measure?: boolean } = {})
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
'window.jQuery': 'jquery',
|
||||
katex: 'katex/dist/katex.js',
|
||||
React: 'react',
|
||||
monaco: 'monaco-editor/esm/vs/editor/editor.api',
|
||||
}),
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/* eslint-disable import/no-import-module-exports */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { size } from '@hydrooj/utils/lib/utils';
|
||||
import cac from 'cac';
|
||||
import chalk from 'chalk';
|
||||
import { build } from 'esbuild';
|
||||
import log from 'fancy-log';
|
||||
import fs from 'fs-extra';
|
||||
import gulp from 'gulp';
|
||||
import webpack from 'webpack';
|
||||
import { sum } from 'lodash';
|
||||
import path from 'path';
|
||||
import webpack, { Stats } from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import pkg from '../package.json';
|
||||
import gulpConfig from './config/gulp';
|
||||
@@ -24,14 +27,15 @@ async function runWebpack({
|
||||
compress: true,
|
||||
hot: true,
|
||||
proxy: {
|
||||
context: (path) => path !== '/ws',
|
||||
context: (p) => p !== '/ws',
|
||||
target: 'http://localhost:2333',
|
||||
ws: true,
|
||||
},
|
||||
}, compiler);
|
||||
return server.start();
|
||||
server.start();
|
||||
return;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const res = await new Promise<Stats>((resolve, reject) => {
|
||||
function compilerCallback(err, stats) {
|
||||
if (err) {
|
||||
console.error(err.stack || err);
|
||||
@@ -42,11 +46,40 @@ async function runWebpack({
|
||||
}
|
||||
if (argv.options.detail) console.log(stats.toString());
|
||||
if (!watch && (!stats || stats.hasErrors())) process.exitCode = 1;
|
||||
resolve(null);
|
||||
resolve(stats);
|
||||
}
|
||||
if (watch) compiler.watch({}, compilerCallback);
|
||||
else compiler.run(compilerCallback);
|
||||
});
|
||||
if (production && res && !res.hasErrors()) {
|
||||
const stats = {};
|
||||
const files = fs.readdirSync(root('public'), { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
if (!file.isFile() || file.name.endsWith('.map')) continue;
|
||||
const data = await fs.stat(path.join(root('public'), file.name));
|
||||
stats[file.name.replace(/\.[a-f0-9]{10}\./, '.')] = data.size;
|
||||
}
|
||||
const statsPath = root('__bundleInfo');
|
||||
if (fs.existsSync(statsPath)) {
|
||||
log('Compare to last production bundle:');
|
||||
const oldStats = JSON.parse(await fs.readFile(statsPath, 'utf-8')) as Record<string, number>;
|
||||
for (const key in stats) if (!oldStats[key]) oldStats[key] = 0;
|
||||
const entries: [filename: string, orig: number, curr: number][] = [];
|
||||
for (const [key, value] of Object.entries(oldStats)) {
|
||||
if (Math.abs((stats[key] || 0) - value) > 25) entries.push([key, value, stats[key] || 0]);
|
||||
}
|
||||
const sorted = entries.sort((i) => i[1] - i[2]);
|
||||
sorted.push(['Total', sum(sorted.map((i) => i[1])), sum(sorted.map((i) => i[2]))]);
|
||||
for (const entry of sorted) {
|
||||
const [name, orig, curr] = entry;
|
||||
const diff = 100 * (curr - orig) / orig;
|
||||
if (Math.abs(diff) < 0.01 && name !== 'Total') continue;
|
||||
const color = orig > curr ? chalk.green : chalk.red;
|
||||
log(color(`${name.padStart(35)} ${size(orig).padStart(10)} -> ${size(curr).padEnd(10)} (${diff.toPrecision(5)}%)`), chalk.reset());
|
||||
}
|
||||
}
|
||||
await fs.writeFile(statsPath, JSON.stringify(stats));
|
||||
}
|
||||
}
|
||||
|
||||
async function runGulp() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import through from 'through2';
|
||||
import nunjucks from 'nunjucks';
|
||||
import through from 'through2';
|
||||
|
||||
export default function compile(data, options = {}) {
|
||||
return through.obj(function (file, encoding, callback) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs-extra';
|
||||
import PluginError from 'plugin-error';
|
||||
import through from 'through2';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
export default function touch(mtime) {
|
||||
async function touchFile(file) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
@import './var.inc.styl'
|
||||
|
||||
.button
|
||||
box-sizing: border-box
|
||||
border: none
|
||||
background: #c0c0c0
|
||||
border-radius: 0
|
||||
min-width: 75px;
|
||||
min-height: 23px;
|
||||
padding: 0 12px;
|
||||
|
||||
&:not(:disabled)
|
||||
&:active
|
||||
box-shadow: --border-sunken-outer, --border-sunken-inner
|
||||
padding: 2px 11px 0 13px;
|
||||
|
||||
.button.inverse
|
||||
line-height: rem($form-control-height - 4)
|
||||
border: 2px solid #FFF
|
||||
background: none
|
||||
|
||||
&, &:visited
|
||||
&, .typo &
|
||||
color: #FFF
|
||||
|
||||
&:not(.disabled)
|
||||
&:hover, &:focus
|
||||
border-color: $immersive-primary-color
|
||||
background: none
|
||||
box-shadow: none
|
||||
&, .typo &
|
||||
color: $immersive-primary-color
|
||||
@@ -1,4 +1,5 @@
|
||||
export default `#include <world.h>
|
||||
export default `\
|
||||
#include <world.h>
|
||||
|
||||
int main() {
|
||||
// ~ Switch on the power line / Remember to put on PROTECTION ~
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
@css {
|
||||
span.cm-comment { color: #008000; }
|
||||
span.cm-keyword, span.cm-variable-3 { line-height: 1em; color: #00f; }
|
||||
span.cm-string { color: #a31515; }
|
||||
span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
|
||||
span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
|
||||
span.cm-variable { color: black; }
|
||||
span.cm-meta { color: #2b91af; }
|
||||
span.cm-link { color: #3a3; }
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import $ from 'jquery';
|
||||
import { AutoloadPage } from 'vj/misc/Page';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import i18n from 'vj/utils/i18n';
|
||||
import request from 'vj/utils/request';
|
||||
import tpl from 'vj/utils/tpl';
|
||||
|
||||
const hitokotoPage = new AutoloadPage('hitokotoPage', () => {
|
||||
export default new NamedPage('homepage', () => {
|
||||
function getHitokoto($containers) {
|
||||
$containers.get().forEach((container) => {
|
||||
request.get('https://v1.hitokoto.cn?c=a&c=b&c=c&c=d&c=e&c=f')
|
||||
@@ -20,10 +20,4 @@ const hitokotoPage = new AutoloadPage('hitokotoPage', () => {
|
||||
});
|
||||
}
|
||||
if ($('[name="hitokoto"]')) getHitokoto($('[name="hitokoto"]'));
|
||||
$(document).on('vjContentNew', (e) => {
|
||||
const elem = $(e.target).find('[name="hitokoto"]');
|
||||
if (elem.get) getHitokoto(elem);
|
||||
});
|
||||
});
|
||||
|
||||
export default hitokotoPage;
|
||||
File renamed without changes.
@@ -1,26 +0,0 @@
|
||||
import $ from 'jquery';
|
||||
import { AutoloadPage } from 'vj/misc/Page';
|
||||
|
||||
const katexPage = new AutoloadPage('katexPage', () => {
|
||||
import('katex/contrib/auto-render/auto-render').then(({ default: katex }) => {
|
||||
function runKatex($containers) {
|
||||
$containers.get().forEach((container) => katex(container, {
|
||||
delimiters: [
|
||||
{ left: '$$', right: '$$', display: true },
|
||||
{ left: '$', right: '$', display: false },
|
||||
{ left: '\\(', right: '\\)', display: false },
|
||||
{ left: '\\[', right: '\\]', display: true },
|
||||
{ left: '\\begin{equation}', right: '\\end{equation}', display: true },
|
||||
{ left: '\\begin{align}', right: '\\end{align}', display: true },
|
||||
{ left: '\\begin{alignat}', right: '\\end{alignat}', display: true },
|
||||
{ left: '\\begin{gather}', right: '\\end{gather}', display: true },
|
||||
{ left: '\\begin{CD}', right: '\\end{CD}', display: true },
|
||||
],
|
||||
}));
|
||||
}
|
||||
runKatex($('.typo'));
|
||||
$(document).on('vjContentNew', (e) => runKatex($(e.target).find('.typo')));
|
||||
});
|
||||
});
|
||||
|
||||
export default katexPage;
|
||||
File renamed without changes.
@@ -1,3 +0,0 @@
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
export default NProgress;
|
||||
@@ -1,5 +1,3 @@
|
||||
import attachObjectMeta from './util/objectMeta';
|
||||
|
||||
export const JOIN_METHOD_NONE = 0;
|
||||
export const JOIN_METHOD_ALL = 1;
|
||||
export const JOIN_METHOD_CODE = 2;
|
||||
@@ -8,7 +6,6 @@ export const JOIN_METHOD_RANGE = {
|
||||
[JOIN_METHOD_ALL]: 'Any user is allowed to join this domain',
|
||||
[JOIN_METHOD_CODE]: 'Any user is allowed to join this domain with an invitation code',
|
||||
};
|
||||
attachObjectMeta(JOIN_METHOD_RANGE, 'intKey', true);
|
||||
|
||||
export const JOIN_EXPIRATION_KEEP_CURRENT = 0;
|
||||
export const JOIN_EXPIRATION_UNLIMITED = -1;
|
||||
@@ -22,4 +19,3 @@ export const JOIN_EXPIRATION_RANGE = {
|
||||
[24 * 30]: 'In 1 month',
|
||||
[JOIN_EXPIRATION_UNLIMITED]: 'Never expire',
|
||||
};
|
||||
attachObjectMeta(JOIN_EXPIRATION_RANGE, 'intKey', true);
|
||||
@@ -1,18 +0,0 @@
|
||||
import attachObjectMeta from './util/objectMeta';
|
||||
|
||||
export const USER_GENDER_MALE = 0;
|
||||
export const USER_GENDER_FEMALE = 1;
|
||||
export const USER_GENDER_OTHER = 2;
|
||||
export const USER_GENDERS = [USER_GENDER_MALE, USER_GENDER_FEMALE, USER_GENDER_OTHER];
|
||||
export const USER_GENDER_RANGE = {
|
||||
[USER_GENDER_MALE]: 'Boy ♂',
|
||||
[USER_GENDER_FEMALE]: 'Girl ♀',
|
||||
[USER_GENDER_OTHER]: 'Other',
|
||||
};
|
||||
attachObjectMeta(USER_GENDER_RANGE, 'intKey', true);
|
||||
export const USER_GENDER_ICONS = {
|
||||
[USER_GENDER_MALE]: '♂',
|
||||
[USER_GENDER_FEMALE]: '♀',
|
||||
[USER_GENDER_OTHER]: '?',
|
||||
};
|
||||
attachObjectMeta(USER_GENDER_ICONS, 'intKey', true);
|
||||
@@ -1,5 +1,3 @@
|
||||
import attachObjectMeta from './util/objectMeta';
|
||||
|
||||
// Please note that accepted < others, rp system uses this feature.
|
||||
export const STATUS_WAITING = 0;
|
||||
export const STATUS_ACCEPTED = 1;
|
||||
@@ -34,7 +32,6 @@ export const STATUS_TEXTS = {
|
||||
[STATUS_FETCHED]: 'Fetched',
|
||||
[STATUS_IGNORED]: 'Ignored',
|
||||
};
|
||||
attachObjectMeta(STATUS_TEXTS, 'intKey', true);
|
||||
|
||||
export const STATUS_CODES = {
|
||||
[STATUS_WAITING]: 'pending',
|
||||
@@ -53,7 +50,6 @@ export const STATUS_CODES = {
|
||||
[STATUS_FETCHED]: 'progress',
|
||||
[STATUS_IGNORED]: 'ignored',
|
||||
};
|
||||
attachObjectMeta(STATUS_CODES, 'intKey', true);
|
||||
|
||||
/**
|
||||
* Whether to show detail about each test case for a submission status
|
||||
@@ -74,7 +70,6 @@ export const STATUS_SCRATCHPAD_SHOW_DETAIL_FLAGS = {
|
||||
[STATUS_FETCHED]: false,
|
||||
[STATUS_IGNORED]: false,
|
||||
};
|
||||
attachObjectMeta(STATUS_SCRATCHPAD_SHOW_DETAIL_FLAGS, 'exportToPython', false);
|
||||
|
||||
/**
|
||||
* Short text to show in Scratchpad mode
|
||||
@@ -86,4 +81,3 @@ export const STATUS_SCRATCHPAD_SHORT_TEXTS = {
|
||||
[STATUS_MEMORY_LIMIT_EXCEEDED]: 'MLE',
|
||||
[STATUS_RUNTIME_ERROR]: 'RTE',
|
||||
};
|
||||
attachObjectMeta(STATUS_SCRATCHPAD_SHORT_TEXTS, 'exportToPython', false);
|
||||
@@ -1,17 +0,0 @@
|
||||
import attachObjectMeta from './util/objectMeta';
|
||||
|
||||
export const PRIVACY_PUBLIC = 0;
|
||||
export const PRIVACY_REGISTERED_ONLY = 1;
|
||||
export const PRIVACY_SECRET = 2;
|
||||
export const PRIVACY_RANGE = {
|
||||
[PRIVACY_PUBLIC]: 'Public',
|
||||
[PRIVACY_REGISTERED_ONLY]: 'Visible to registered users',
|
||||
[PRIVACY_SECRET]: 'Secret',
|
||||
};
|
||||
attachObjectMeta(PRIVACY_RANGE, 'intKey', true);
|
||||
|
||||
export const FUNCTION_RANGE = {
|
||||
0: 'Disabled',
|
||||
1: 'Enabled',
|
||||
};
|
||||
attachObjectMeta(FUNCTION_RANGE, 'intKey', true);
|
||||
@@ -1,8 +0,0 @@
|
||||
export default function attachObjectMeta(obj, key, value) {
|
||||
Object.defineProperty(obj, `__${key}`, {
|
||||
value,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import './utils/i18n';
|
||||
import './utils/loadReactRedux';
|
||||
import './utils/mediaQuery';
|
||||
import './utils/mongoId';
|
||||
import './utils/parseQueryString';
|
||||
import './utils/pipeStream';
|
||||
import './utils/pjax';
|
||||
import './utils/request';
|
||||
@@ -16,7 +15,6 @@ import './utils/zip';
|
||||
import './components/autocomplete';
|
||||
import './components/dialog';
|
||||
import './components/notification';
|
||||
import './components/nprogress';
|
||||
import './components/monaco/loader';
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
@@ -88,7 +88,6 @@ async function handleClickUpload(files) {
|
||||
Notification.success(i18n('File uploaded successfully.'));
|
||||
await pjax.request({ push: false });
|
||||
} catch (e) {
|
||||
window.captureException?.(e);
|
||||
console.error(e);
|
||||
Notification.error(i18n('File upload failed: {0}', e.toString()));
|
||||
} finally {
|
||||
|
||||
@@ -7,7 +7,6 @@ import VjNotification from 'vj/components/notification';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import api, { gql } from 'vj/utils/api';
|
||||
import loadReactRedux from 'vj/utils/loadReactRedux';
|
||||
import parseQueryString from 'vj/utils/parseQueryString';
|
||||
|
||||
const page = new NamedPage('home_messages', () => {
|
||||
let reduxStore;
|
||||
@@ -92,10 +91,10 @@ const page = new NamedPage('home_messages', () => {
|
||||
* A target user id may be assigned in the query string.
|
||||
*/
|
||||
async function loadSendTarget() {
|
||||
const queryString = parseQueryString();
|
||||
if (!queryString.target) return;
|
||||
const target = new URL(window.location.href).searchParams.get('target');
|
||||
if (!target) return;
|
||||
const user = await api(gql`
|
||||
users(search: ${queryString.target}, exact: true) {
|
||||
users(search: ${target}, exact: true) {
|
||||
_id
|
||||
uname
|
||||
avatarUrl
|
||||
|
||||
@@ -100,7 +100,6 @@ const page = new NamedPage('problem_files', () => {
|
||||
Notification.success(i18n('File uploaded successfully.'));
|
||||
await pjax.request({ push: false });
|
||||
} catch (e) {
|
||||
window.captureException?.(e);
|
||||
console.error(e);
|
||||
Notification.error(i18n('File upload failed: {0}', e.toString()));
|
||||
} finally {
|
||||
|
||||
@@ -25,7 +25,6 @@ import 'vj/misc/section.styl';
|
||||
import 'vj/misc/nothing.styl';
|
||||
import 'vj/components/editor/cmeditor.styl';
|
||||
import 'vj/components/datepicker/datepicker.styl';
|
||||
import 'vj/components/katex/katex.styl';
|
||||
|
||||
// load all page stylesheets
|
||||
const pageStyleReq = require.context('../', true, /\.page\.styl$/i);
|
||||
|
||||
@@ -3,4 +3,4 @@ declare let UserContext: any;
|
||||
declare let UiContext: any;
|
||||
// eslint-disable-next-line camelcase
|
||||
declare let node_modules: any;
|
||||
declare let LANGS: Record<string, import('@hydrooj/utils/lib/lang').LangConfig>;
|
||||
declare let LANGS: Record<string, any>;
|
||||
@@ -1,6 +0,0 @@
|
||||
export default function cloneAttributes(from, to) {
|
||||
const attributes = from.prop('attributes');
|
||||
$.each(attributes, function () {
|
||||
to.attr(this.name, this.value);
|
||||
});
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export default function parseQueryString(str) {
|
||||
const obj = {};
|
||||
(str || document.location.search)
|
||||
.replace(/(^\?)/, '')
|
||||
.split('&')
|
||||
.forEach((n) => {
|
||||
const [key, value] = n.split('=').map((v) => decodeURIComponent(v));
|
||||
obj[key] = value;
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
window.Hydro.utils.parseQueryString = parseQueryString;
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
import $ from 'jquery';
|
||||
import { nanoid } from 'nanoid';
|
||||
import NProgress from 'nprogress';
|
||||
import Notification from 'vj/components/notification';
|
||||
import NProgress from 'vj/components/nprogress';
|
||||
import request from 'vj/utils/request';
|
||||
|
||||
const pjax = {};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
type Substitution = string | { templateRaw: true, html: string };
|
||||
type Substitution = string | number | { templateRaw: true, html: string };
|
||||
|
||||
export default function tpl(pieces: TemplateStringsArray, ...substitutions: Substitution[]) {
|
||||
let result = pieces[0];
|
||||
|
||||
Reference in new issue
Block a user