mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-25 12:08:30 +00:00
The Great Webpack Update.
* Update to version 4 of webpack. * For that matter, update *every dependency* to the latest available version. * Remove the babel build target for Edge, as it doesn't seem to be necessary with webpack 4 and tenser. * Add support for optional chaining and nullish coalescing via Babel transformations. * Update the clips domain version to work better. Or at all, really. * Remove unused code from i18n. * Remove the last `<style>` from vue component files. They don't work that way now anyways. * Fix a bug in Raven's report handler. * Fix a bug with the menu button in browsers that don't understand `:scope` within `querySelector()`.
This commit is contained in:
parent
567708b7f1
commit
014eb203c3
31 changed files with 3106 additions and 5715 deletions
7
.babelrc
7
.babelrc
|
@ -1,8 +1,7 @@
|
||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
["transform-react-jsx", {
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"pragma": "createElement"
|
"@babel/plugin-proposal-nullish-coalescing-operator"
|
||||||
}]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
8013
package-lock.json
generated
8013
package-lock.json
generated
File diff suppressed because it is too large
Load diff
83
package.json
83
package.json
|
@ -7,47 +7,47 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --config webpack.web.dev.js",
|
"start": "webpack-dev-server --config webpack.web.dev.js",
|
||||||
"eslint": "eslint \"src/**/*.{js,jsx,vue}\"",
|
"eslint": "eslint \"src/**/*.{js,jsx,vue}\"",
|
||||||
|
"clean": "rimraf dist",
|
||||||
"dev": "webpack-dev-server --config webpack.web.dev.js",
|
"dev": "webpack-dev-server --config webpack.web.dev.js",
|
||||||
"dev:clips": "webpack-dev-server --config webpack.clips.dev.js",
|
"dev:clips": "webpack-dev-server --config webpack.clips.dev.js",
|
||||||
"dev:babel": "webpack-dev-server --config webpack.web.dev.babel.js",
|
"dev:prod": "webpack-dev-server --config webpack.web.dev.prod.js",
|
||||||
"build:all": "npm run build && npm run build:clips",
|
"build:all": "npm run build && npm run build:clips",
|
||||||
"build": "npm run build:prod && npm run build:babel",
|
"build": "npm run build:prod",
|
||||||
"build:clips": "npm run build:clips:prod && npm run build:clips:babel",
|
"build:clips": "cross-env NODE_ENV=production webpack --config webpack.clips.prod.js",
|
||||||
"build:clips:prod": "webpack --config webpack.clips.prod.js --define process.env.NODE_ENV='production'",
|
"build:stats": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js --json > stats.json",
|
||||||
"build:clips:babel": "webpack --config webpack.clips.babel.js --define process.env.NODE_ENV='production'",
|
"build:prod": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js",
|
||||||
"build:stats": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production' --json > stats.json",
|
"build:dev": "npm run clean && webpack --config webpack.web.dev.js"
|
||||||
"build:babel": "webpack --config webpack.web.babel.js --define process.env.NODE_ENV='production'",
|
|
||||||
"build:prod": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production'",
|
|
||||||
"build:dev": "webpack --config webpack.web.dev.js"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.3",
|
"@babel/core": "^7.4.5",
|
||||||
"babel-eslint": "^8.2.3",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
|
||||||
"babel-loader": "^7.1.4",
|
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||||
"babel-plugin-transform-react-jsx": "^6.24.1",
|
"@babel/plugin-transform-react-jsx": "^7.3.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-eslint": "^10.0.2",
|
||||||
"babel-preset-env": "^1.7.0",
|
"babel-loader": "^8.0.6",
|
||||||
"clean-webpack-plugin": "^0.1.19",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"copy-webpack-plugin": "^4.5.1",
|
"copy-webpack-plugin": "^5.0.3",
|
||||||
"css-loader": "^0.28.11",
|
"cross-env": "^5.2.0",
|
||||||
"eslint": "^4.19.1",
|
"css-loader": "^3.0.0",
|
||||||
"eslint-plugin-react": "^7.7.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-plugin-vue": "^4.5.0",
|
"eslint-plugin-react": "^7.13.0",
|
||||||
"extract-loader": "^1.0.2",
|
"eslint-plugin-vue": "^5.2.2",
|
||||||
"file-loader": "^1.1.11",
|
"extract-loader": "^2.0.1",
|
||||||
"node-sass": "^4.11.0",
|
"file-loader": "^4.0.0",
|
||||||
"raw-loader": "^0.5.1",
|
"json-loader": "^0.5.7",
|
||||||
"sass-loader": "^6.0.7",
|
"node-sass": "^4.12.0",
|
||||||
"style-loader": "^0.18.2",
|
"raw-loader": "^3.0.0",
|
||||||
"to-string-loader": "^1.1.5",
|
"rimraf": "^2.6.3",
|
||||||
"uglifyjs-webpack-plugin": "^1.2.5",
|
"sass-loader": "^7.1.0",
|
||||||
"vue-loader": "^13.7.3",
|
"terser-webpack-plugin": "^1.3.0",
|
||||||
"webpack": "^3.11.0",
|
"vue-loader": "^15.7.0",
|
||||||
"webpack-dev-middleware": "^1.12.2",
|
"vue-template-compiler": "^2.6.10",
|
||||||
"webpack-dev-server": "^2.11.2",
|
"webpack": "^4.34.0",
|
||||||
"webpack-manifest-plugin": "^1.3.2",
|
"webpack-cli": "^3.3.4",
|
||||||
"webpack-merge": "^4.1.2"
|
"webpack-dev-server": "^3.7.2",
|
||||||
|
"webpack-manifest-plugin": "^2.0.4",
|
||||||
|
"webpack-merge": "^4.2.1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -58,24 +58,23 @@
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
"dayjs": "^1.7.7",
|
"dayjs": "^1.7.7",
|
||||||
"displacejs": "^1.2.4",
|
"displacejs": "^1.2.4",
|
||||||
"emoji-regex": "^6.5.1",
|
"emoji-regex": "^8.0.0",
|
||||||
"file-saver": "^2.0.1",
|
"file-saver": "^2.0.1",
|
||||||
"graphql": "^0.13.2",
|
"graphql": "^14.3.1",
|
||||||
"graphql-tag": "^2.9.1",
|
"graphql-tag": "^2.9.1",
|
||||||
"js-cookie": "^2.2.0",
|
"js-cookie": "^2.2.0",
|
||||||
"markdown-it": "^8.4.1",
|
"markdown-it": "^8.4.1",
|
||||||
"markdown-it-link-attributes": "^2.1.0",
|
"markdown-it-link-attributes": "^2.1.0",
|
||||||
"path-to-regexp": "^2.2.1",
|
"path-to-regexp": "^3.0.0",
|
||||||
"popper.js": "^1.14.3",
|
"popper.js": "^1.14.3",
|
||||||
"raven-js": "^3.24.2",
|
"raven-js": "^3.24.2",
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.1",
|
||||||
"safe-regex": "^1.1.0",
|
"safe-regex": "^2.0.2",
|
||||||
"sortablejs": "^1.9.0",
|
"sortablejs": "^1.10.0-rc2",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"vue-clickaway": "^2.2.2",
|
"vue-clickaway": "^2.2.2",
|
||||||
"vue-color": "^2.4.6",
|
"vue-color": "^2.4.6",
|
||||||
"vue-observe-visibility": "^0.4.4",
|
"vue-observe-visibility": "^0.4.4",
|
||||||
"vue-template-compiler": "^2.6.10",
|
|
||||||
"vuedraggable": "^2.16.0"
|
"vuedraggable": "^2.16.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,13 @@
|
||||||
|
|
||||||
const DEBUG = localStorage.ffzDebugMode == 'true' && document.body.classList.contains('ffz-dev') && ! window.Ember,
|
const DEBUG = localStorage.ffzDebugMode == 'true' && document.body.classList.contains('ffz-dev') && ! window.Ember,
|
||||||
SERVER = DEBUG ? '//localhost:8000' : '//cdn.frankerfacez.com',
|
SERVER = DEBUG ? '//localhost:8000' : '//cdn.frankerfacez.com',
|
||||||
BABEL = /Edge/.test(window.navigator.userAgent) ? 'babel/' : '',
|
|
||||||
CLIPS = /clips\.twitch\.tv/.test(location.hostname) ? 'clips/' : '',
|
CLIPS = /clips\.twitch\.tv/.test(location.hostname) ? 'clips/' : '',
|
||||||
FLAVOR = window.Ember ? 'umbral' : 'avalon',
|
|
||||||
|
|
||||||
script = document.createElement('script');
|
script = document.createElement('script');
|
||||||
|
|
||||||
script.id = 'ffz-script';
|
script.id = 'ffz-script';
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.crossOrigin = 'anonymous';
|
script.crossOrigin = 'anonymous';
|
||||||
script.src = `${SERVER}/script/${CLIPS}${BABEL}${FLAVOR}.js?_=${Date.now()}`;
|
script.src = `${SERVER}/script/${CLIPS}avalon.js?_=${Date.now()}`;
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
})();
|
})();
|
|
@ -22,7 +22,7 @@ const OVERRIDE_COOKIE = 'experiment_overrides',
|
||||||
// We want to import this so that the file is included in the output.
|
// We want to import this so that the file is included in the output.
|
||||||
// We don't load using this because we might want a newer file from the
|
// We don't load using this because we might want a newer file from the
|
||||||
// server.
|
// server.
|
||||||
import EXPERIMENTS from 'file-loader?name=[name].[hash].[ext]!./experiments.json'; // eslint-disable-line no-unused-vars
|
import EXPERIMENTS from './experiments.json'; // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
194
src/i18n.js
194
src/i18n.js
|
@ -12,7 +12,6 @@ import Module from 'utilities/module';
|
||||||
|
|
||||||
import NewTransCore from 'utilities/translation-core';
|
import NewTransCore from 'utilities/translation-core';
|
||||||
|
|
||||||
|
|
||||||
const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'UwU', '>w<', '^w^', '> w >', 'v.v'],
|
const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'UwU', '>w<', '^w^', '> w >', 'v.v'],
|
||||||
|
|
||||||
transformText = (ast, fn) => {
|
transformText = (ast, fn) => {
|
||||||
|
@ -428,203 +427,12 @@ export class TranslationManager extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TranslationCore
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
const REPLACE = String.prototype.replace; /*,
|
|
||||||
SPLIT = String.prototype.split;
|
|
||||||
|
|
||||||
const DEFAULT_FORMATTERS = {
|
|
||||||
en_plural: n => n !== 1 ? 's' : '',
|
|
||||||
number: (n, locale) => n.toLocaleString(locale)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default class TranslationCore {
|
|
||||||
constructor(options) {
|
|
||||||
options = options || {};
|
|
||||||
this.warn = options.warn;
|
|
||||||
this.phrases = new Map;
|
|
||||||
this.extend(options.phrases);
|
|
||||||
this.locale = options.locale || 'en';
|
|
||||||
this.defaultLocale = options.defaultLocale || this.locale;
|
|
||||||
this.transformation = null;
|
|
||||||
|
|
||||||
const allowMissing = options.allowMissing ? transformPhrase : null;
|
|
||||||
this.onMissingKey = typeof options.onMissingKey === 'function' ? options.onMissingKey : allowMissing;
|
|
||||||
this.transformPhrase = typeof options.transformPhrase === 'function' ? options.transformPhrase : transformPhrase;
|
|
||||||
this.transformList = typeof options.transformList === 'function' ? options.transformList : transformList;
|
|
||||||
this.delimiter = options.delimiter || /\s*\|\|\|\|\s/;
|
|
||||||
this.tokenRegex = options.tokenRegex || /%\{(.*?)(?:\|(.*?))?\}/g;
|
|
||||||
this.formatters = Object.assign({}, DEFAULT_FORMATTERS, options.formatters || {});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
formatNumber(value) {
|
|
||||||
return value.toLocaleString(this.locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extend(phrases, prefix) {
|
|
||||||
const added = [];
|
|
||||||
for(const key in phrases)
|
|
||||||
if ( has(phrases, key) ) {
|
|
||||||
let phrase = phrases[key];
|
|
||||||
const pref_key = prefix ? key === '_' ? prefix : `${prefix}.${key}` : key;
|
|
||||||
|
|
||||||
if ( typeof phrase === 'object' )
|
|
||||||
added.push(...this.extend(phrase, pref_key));
|
|
||||||
else {
|
|
||||||
if ( typeof phrase === 'string' && phrase.indexOf(this.delimiter) !== -1 )
|
|
||||||
phrase = SPLIT.call(phrase, this.delimiter);
|
|
||||||
this.phrases.set(pref_key, phrase);
|
|
||||||
added.push(pref_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
unset(phrases, prefix) {
|
|
||||||
if ( typeof phrases === 'string' )
|
|
||||||
phrases = [phrases];
|
|
||||||
|
|
||||||
const keys = Array.isArray(phrases) ? phrases : Object.keys(phrases);
|
|
||||||
for(const key of keys) {
|
|
||||||
const pref_key = prefix ? `${prefix}.${key}` : key;
|
|
||||||
const phrase = phrases[key];
|
|
||||||
if ( typeof phrase === 'object' )
|
|
||||||
this.unset(phrase, pref_key);
|
|
||||||
else
|
|
||||||
this.phrases.delete(pref_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
has(key) {
|
|
||||||
return this.phrases.has(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key, phrase) {
|
|
||||||
if ( typeof phrase === 'string' && phrase.indexOf(this.delimiter) !== -1 )
|
|
||||||
phrase = SPLIT.call(phrase, this.delimiter);
|
|
||||||
|
|
||||||
this.phrases.set(key, phrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.phrases.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
replace(phrases) {
|
|
||||||
this.clear();
|
|
||||||
this.extend(phrases);
|
|
||||||
}
|
|
||||||
|
|
||||||
preT(key, phrase, options, use_default) {
|
|
||||||
const opts = options == null ? {} : options;
|
|
||||||
let p, locale;
|
|
||||||
|
|
||||||
if ( use_default ) {
|
|
||||||
p = phrase;
|
|
||||||
locale = this.defaultLocale;
|
|
||||||
|
|
||||||
} else if ( key === undefined && phrase ) {
|
|
||||||
p = phrase;
|
|
||||||
locale = this.defaultLocale;
|
|
||||||
if ( this.warn )
|
|
||||||
this.warn(`Translation key not generated with phrase "${phrase}"`);
|
|
||||||
|
|
||||||
} else if ( this.phrases.has(key) ) {
|
|
||||||
p = this.phrases.get(key);
|
|
||||||
locale = this.locale;
|
|
||||||
} else if ( phrase ) {
|
|
||||||
if ( this.warn && this.locale !== this.defaultLocale )
|
|
||||||
this.warn(`Missing translation for key "${key}" in locale "${this.locale}"`);
|
|
||||||
|
|
||||||
p = phrase;
|
|
||||||
locale = this.defaultLocale;
|
|
||||||
} else if ( this.onMissingKey )
|
|
||||||
return this.onMissingKey(key, opts, this.locale, this.tokenRegex, this.formatters);
|
|
||||||
else {
|
|
||||||
if ( this.warn )
|
|
||||||
this.warn(`Missing translation for key "${key}" in locale "${this.locale}"`);
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.transformation )
|
|
||||||
p = this.transformation(key, p, opts, locale, this.tokenRegex);
|
|
||||||
|
|
||||||
return [p, opts, locale];
|
|
||||||
}
|
|
||||||
|
|
||||||
t(key, phrase, options, use_default) {
|
|
||||||
const [p, opts, locale] = this.preT(key, phrase, options, use_default);
|
|
||||||
|
|
||||||
return this.transformPhrase(p, opts, locale, this.tokenRegex, this.formatters);
|
|
||||||
}
|
|
||||||
|
|
||||||
tList(key, phrase, options, use_default) {
|
|
||||||
const [p, opts, locale] = this.preT(key, phrase, options, use_default);
|
|
||||||
|
|
||||||
return this.transformList(p, opts, locale, this.tokenRegex, this.formatters);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Transformations
|
// Transformations
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
const DOLLAR_REGEX = /\$/g;
|
const DOLLAR_REGEX = /\$/g;
|
||||||
|
const REPLACE = String.prototype.replace;
|
||||||
export function transformList(phrase, substitutions, locale, token_regex, formatters) {
|
|
||||||
const is_array = Array.isArray(phrase);
|
|
||||||
if ( substitutions == null )
|
|
||||||
return is_array ? phrase[0] : phrase;
|
|
||||||
|
|
||||||
let p = phrase;
|
|
||||||
const options = typeof substitutions === 'number' ? {count: substitutions} : substitutions;
|
|
||||||
|
|
||||||
if ( is_array )
|
|
||||||
p = p[0];
|
|
||||||
|
|
||||||
const result = [];
|
|
||||||
|
|
||||||
token_regex.lastIndex = 0;
|
|
||||||
let idx = 0, match;
|
|
||||||
|
|
||||||
while((match = token_regex.exec(p))) {
|
|
||||||
const nix = match.index,
|
|
||||||
arg = match[1],
|
|
||||||
fmt = match[2];
|
|
||||||
|
|
||||||
if ( nix !== idx )
|
|
||||||
result.push(p.slice(idx, nix));
|
|
||||||
|
|
||||||
let val = get(arg, options);
|
|
||||||
|
|
||||||
if ( val != null ) {
|
|
||||||
const formatter = formatters[fmt];
|
|
||||||
if ( typeof formatter === 'function' )
|
|
||||||
val = formatter(val, locale, options);
|
|
||||||
else if ( typeof val === 'string' )
|
|
||||||
val = REPLACE.call(val, DOLLAR_REGEX, '$$');
|
|
||||||
|
|
||||||
result.push(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = nix + match[0].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( idx < p.length )
|
|
||||||
result.push(p.slice(idx));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function transformPhrase(phrase, substitutions, locale, token_regex, formatters) {
|
export function transformPhrase(phrase, substitutions, locale, token_regex, formatters) {
|
||||||
const is_array = Array.isArray(phrase);
|
const is_array = Array.isArray(phrase);
|
||||||
|
|
|
@ -151,7 +151,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`
|
||||||
FrankerFaceZ.Logger = Logger;
|
FrankerFaceZ.Logger = Logger;
|
||||||
|
|
||||||
const VER = FrankerFaceZ.version_info = {
|
const VER = FrankerFaceZ.version_info = {
|
||||||
major: 4, minor: 5, revision: 2,
|
major: 4, minor: 5, revision: 3,
|
||||||
commit: __git_commit__,
|
commit: __git_commit__,
|
||||||
build: __webpack_hash__,
|
build: __webpack_hash__,
|
||||||
toString: () =>
|
toString: () =>
|
||||||
|
|
|
@ -120,26 +120,4 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.ffz--example-report {
|
|
||||||
div {
|
|
||||||
max-height: 30rem;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: monospace;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ffz--report-upload {
|
|
||||||
z-index: 1;
|
|
||||||
position: absolute;
|
|
||||||
top: 1rem;
|
|
||||||
right: 3rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -176,7 +176,7 @@ export default class RavenLogger extends Module {
|
||||||
const exc = data.exception && data.exception.values[0];
|
const exc = data.exception && data.exception.values[0];
|
||||||
|
|
||||||
// We don't want any of Sentry's junk.
|
// We don't want any of Sentry's junk.
|
||||||
if ( data.message && data.messages.includes('raven-js/') || (exc && JSON.stringify(exc).includes('raven-js/')) )
|
if ( data.message && data.message.includes('raven-js/') || (exc && JSON.stringify(exc).includes('raven-js/')) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We don't want any of Mozilla's junk either.
|
// We don't want any of Mozilla's junk either.
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default class Clippy extends BaseSite {
|
||||||
this.inject(Fine);
|
this.inject(Fine);
|
||||||
this.inject(Apollo, false);
|
this.inject(Apollo, false);
|
||||||
|
|
||||||
this.inject(Switchboard);
|
//this.inject(Switchboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
|
|
@ -49,6 +49,7 @@ export default class Chat extends Module {
|
||||||
|
|
||||||
this.ChatController.on('mount', this.chatMounted, this);
|
this.ChatController.on('mount', this.chatMounted, this);
|
||||||
this.ChatController.on('unmount', this.chatMounted, this);
|
this.ChatController.on('unmount', this.chatMounted, this);
|
||||||
|
this.ChatController.on('update', this.chatUpdated, this);
|
||||||
this.ChatController.on('receive-props', this.chatUpdated, this);
|
this.ChatController.on('receive-props', this.chatUpdated, this);
|
||||||
|
|
||||||
this.ChatController.ready((cls, instances) => {
|
this.ChatController.ready((cls, instances) => {
|
||||||
|
@ -167,7 +168,7 @@ export default class Chat extends Module {
|
||||||
|
|
||||||
|
|
||||||
chatUpdated(chat, props) {
|
chatUpdated(chat, props) {
|
||||||
if ( get('data.clip.broadcaster.id', props) !== get('data.clip.broadcaster.id', chat.props) ) {
|
if ( ! chat._ffz_room || props?.data?.clip?.broadcaster?.id !== chat._ffz_room.id ) {
|
||||||
this.chatUmounted(chat);
|
this.chatUmounted(chat);
|
||||||
this.chatMounted(chat, props);
|
this.chatMounted(chat, props);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default class CSSTweaks extends Module {
|
||||||
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
||||||
for(const key of raw.keys()) {
|
for(const key of raw.keys()) {
|
||||||
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
||||||
this.chunks[k] = raw(key);
|
this.chunks[k] = raw(key).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chunks_loaded = true;
|
this.chunks_loaded = true;
|
||||||
|
|
|
@ -163,7 +163,7 @@ export default class ChannelBar extends Module {
|
||||||
|
|
||||||
updateMetadata(inst, keys) {
|
updateMetadata(inst, keys) {
|
||||||
const container = this.fine.getChildNode(inst),
|
const container = this.fine.getChildNode(inst),
|
||||||
metabar = container && container.querySelector && container.querySelector('.channel-info-bar__action-container > .tw-flex,.channel-info-bar__content-right > .tw-align-items-start > .tw-flex:last-child');
|
metabar = container?.querySelector?.('.channel-info-bar__action-container > .tw-flex,.channel-info-bar__content-right > .tw-align-items-start > .tw-flex:last-child');
|
||||||
|
|
||||||
if ( ! inst._ffz_mounted || ! metabar )
|
if ( ! inst._ffz_mounted || ! metabar )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -332,7 +332,7 @@ export default class CSSTweaks extends Module {
|
||||||
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
||||||
for(const key of raw.keys()) {
|
for(const key of raw.keys()) {
|
||||||
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
||||||
this.chunks[k] = raw(key);
|
this.chunks[k] = raw(key).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chunks_loaded = true;
|
this.chunks_loaded = true;
|
||||||
|
|
|
@ -118,7 +118,11 @@ export default class MenuButton extends SiteModule {
|
||||||
if ( ! container )
|
if ( ! container )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const user_stuff = container.querySelector(':scope > .tw-justify-content-end:last-child');
|
let user_stuff = null;
|
||||||
|
try {
|
||||||
|
user_stuff = container.querySelector(':scope > .tw-justify-content-end:last-child');
|
||||||
|
} catch(err) { /* dumb browsers with no :scope are dumb */ }
|
||||||
|
|
||||||
if ( user_stuff )
|
if ( user_stuff )
|
||||||
container = user_stuff;
|
container = user_stuff;
|
||||||
else
|
else
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<figure :class="[(isOpen || ! val || ! val.length) ? 'ffz-i-search' : val]" />
|
<figure :class="[(isOpen || ! val || ! val.length) ? 'ffz-i-search' : val]" />
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
ref="input"
|
|
||||||
:id="'icon-search$' + id"
|
:id="'icon-search$' + id"
|
||||||
|
ref="input"
|
||||||
:placeholder="('setting.icon.search', 'Search for Icon')"
|
:placeholder="('setting.icon.search', 'Search for Icon')"
|
||||||
:value="isOpen ? search : val"
|
:value="isOpen ? search : val"
|
||||||
:class="[clearable ? 'tw-pd-r-5' : 'tw-pd-r-1']"
|
:class="[clearable ? 'tw-pd-r-5' : 'tw-pd-r-1']"
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<balloon v-if="open" :dir="direction" color="background-base">
|
<balloon v-if="open" :dir="direction" color="background-base">
|
||||||
<div ref="list">
|
<div ref="list">
|
||||||
<simplebar classes="scrollable-area--suppress-scroll-x ffz--icon-picker__list">
|
<simplebar classes="scrollable-area--suppress-scroll-x ffz--icon-picker__list">
|
||||||
<div v-if="visible.length" role="radiogroup" class="tw-pd-1 tw-flex tw-flex-wrap tw-justify-content-between" >
|
<div v-if="visible.length" role="radiogroup" class="tw-pd-1 tw-flex tw-flex-wrap tw-justify-content-between">
|
||||||
<div
|
<div
|
||||||
v-for="i of visible"
|
v-for="i of visible"
|
||||||
:key="i[0]"
|
:key="i[0]"
|
||||||
|
@ -205,7 +205,7 @@ export default {
|
||||||
return this.icons;
|
return this.icons;
|
||||||
|
|
||||||
const search = this.search.toLowerCase().replace(' ', '-'),
|
const search = this.search.toLowerCase().replace(' ', '-'),
|
||||||
reg = new RegExp('(?:^|-| )' + escape_regex(search), 'i');
|
reg = new RegExp(`(?:^|-| )${escape_regex(search)}`, 'i');
|
||||||
|
|
||||||
return this.icons.filter(x => reg.test(x[1]));
|
return this.icons.filter(x => reg.test(x[1]));
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<div v-html="output" />
|
<div v-html="output" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
import {has, once} from 'utilities/object';
|
import {has} from 'utilities/object';
|
||||||
|
|
||||||
|
|
||||||
let last_muncher = 0;
|
let last_muncher = 0;
|
||||||
|
|
|
@ -32,8 +32,8 @@ export function duration_to_string(elapsed, separate_days, days_only, no_hours,
|
||||||
|
|
||||||
|
|
||||||
export function print_duration(seconds) {
|
export function print_duration(seconds) {
|
||||||
let minutes = Math.floor(seconds / 60),
|
let minutes = Math.floor(seconds / 60);
|
||||||
hours = Math.floor(minutes / 60);
|
const hours = Math.floor(minutes / 60);
|
||||||
|
|
||||||
minutes %= 60;
|
minutes %= 60;
|
||||||
seconds %= 60;
|
seconds %= 60;
|
||||||
|
|
|
@ -445,7 +445,7 @@ export default class TranslationCore {
|
||||||
if ( locale == null )
|
if ( locale == null )
|
||||||
locale = this.locale;
|
locale = this.locale;
|
||||||
|
|
||||||
let val = get(node.v, data);
|
const val = get(node.v, data);
|
||||||
if ( val == null )
|
if ( val == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default class TwitchData extends Module {
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
getStreamMeta(id, login) {
|
getStreamMeta(id, login) {
|
||||||
return new Promise(async (s, f) => {
|
return new Promise((s, f) => {
|
||||||
if ( id ) {
|
if ( id ) {
|
||||||
if ( this._waiting_stream_ids.has(id) )
|
if ( this._waiting_stream_ids.has(id) )
|
||||||
this._waiting_stream_ids.get(id).push([s, f]);
|
this._waiting_stream_ids.get(id).push([s, f]);
|
||||||
|
|
|
@ -279,4 +279,24 @@ textarea.tw-input {
|
||||||
|
|
||||||
.ffz--button-disable {
|
.ffz--button-disable {
|
||||||
@include button-colors(#bd0f0f, #fff, 6px);
|
@include button-colors(#bd0f0f, #fff, 6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz--example-report {
|
||||||
|
div {
|
||||||
|
max-height: 30rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: monospace;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz--report-upload {
|
||||||
|
z-index: 1;
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 3rem;
|
||||||
}
|
}
|
|
@ -1,82 +0,0 @@
|
||||||
const webpack = require('webpack');
|
|
||||||
const merge = require('webpack-merge');
|
|
||||||
const common = require('./webpack.clips.common.js');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const CleanPlugin = require('clean-webpack-plugin');
|
|
||||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
|
||||||
|
|
||||||
const commit_hash = require('child_process').execSync('git rev-parse HEAD').toString().trim();
|
|
||||||
|
|
||||||
/* global module __dirname */
|
|
||||||
|
|
||||||
const config = module.exports = merge(common, {
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
plugins: ['transform-es2015-classes']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new CleanPlugin(['dist/clips/babel']),
|
|
||||||
new UglifyJSPlugin({
|
|
||||||
sourceMap: true,
|
|
||||||
uglifyOptions: {
|
|
||||||
compress: {
|
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
keep_classnames: true,
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__git_commit__: JSON.stringify(commit_hash)
|
|
||||||
}),
|
|
||||||
new ManifestPlugin({
|
|
||||||
basePath: 'clips/babel/',
|
|
||||||
publicPath: 'clips/babel/',
|
|
||||||
map: data => {
|
|
||||||
if ( data.name.endsWith('.scss') )
|
|
||||||
data.name = `${data.name.substr(0,data.name.length - 5)}.css`;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
output: {
|
|
||||||
publicPath: '//cdn.frankerfacez.com/static/clips/babel/',
|
|
||||||
path: path.resolve(__dirname, 'dist/clips/babel'),
|
|
||||||
filename: '[name].[hash].js'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// This is why we can't have nice things.
|
|
||||||
// Why can't I just access process.env.NODE_ENV from
|
|
||||||
// one of these files when I set it with webpack's
|
|
||||||
// CLI? So stupid.
|
|
||||||
//
|
|
||||||
// So here we go.
|
|
||||||
// This is crap.
|
|
||||||
// But it works.
|
|
||||||
|
|
||||||
for(const rule of config.module.rules) {
|
|
||||||
if ( Array.isArray(rule.use) )
|
|
||||||
for(const use of rule.use)
|
|
||||||
if ( use.options && use.options.name && use.options.name.startsWith('[name].') )
|
|
||||||
use.options.name = `[name].[hash].${use.options.name.slice(7)}`;
|
|
||||||
}
|
|
|
@ -9,6 +9,7 @@ const webpack = require('webpack');
|
||||||
/* global module */
|
/* global module */
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -39,7 +40,7 @@ module.exports = merge(common, {
|
||||||
|
|
||||||
proxy: {
|
proxy: {
|
||||||
'**': {
|
'**': {
|
||||||
target: 'http://cdn.frankerfacez.com/',
|
target: 'https://cdn.frankerfacez.com/',
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -68,6 +69,7 @@ module.exports = merge(common, {
|
||||||
output: {
|
output: {
|
||||||
publicPath: '//localhost:8000/script/clips/',
|
publicPath: '//localhost:8000/script/clips/',
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
jsonpFunction: 'ffzWebpackJsonp'
|
jsonpFunction: 'ffzWebpackJsonp',
|
||||||
|
crossOriginLoading: 'anonymous'
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -4,11 +4,11 @@ const common = require('./webpack.clips.common.js');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||||
const CleanPlugin = require('clean-webpack-plugin');
|
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
||||||
|
|
||||||
const uglify = require('uglify-es');
|
const Terser = require('terser');
|
||||||
|
|
||||||
// Get Git info
|
// Get Git info
|
||||||
|
|
||||||
|
@ -16,24 +16,25 @@ const commit_hash = require('child_process').execSync('git rev-parse HEAD').toSt
|
||||||
|
|
||||||
/* global module Buffer __dirname */
|
/* global module Buffer __dirname */
|
||||||
|
|
||||||
const config = module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
|
mode: 'production',
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
|
|
||||||
plugins: [
|
optimization: {
|
||||||
new CleanPlugin(['dist/clips']),
|
concatenateModules: false,
|
||||||
new UglifyJSPlugin({
|
minimizer: [
|
||||||
sourceMap: true,
|
new TerserPlugin({
|
||||||
uglifyOptions: {
|
sourceMap: true,
|
||||||
compress: {
|
terserOptions: {
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
keep_classnames: true,
|
keep_classnames: true,
|
||||||
keep_fnames: true
|
keep_fnames: true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}),
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
__git_commit__: JSON.stringify(commit_hash)
|
__git_commit__: JSON.stringify(commit_hash)
|
||||||
}),
|
}),
|
||||||
|
@ -43,7 +44,7 @@ const config = module.exports = merge(common, {
|
||||||
to: 'script.min.js',
|
to: 'script.min.js',
|
||||||
transform: content => {
|
transform: content => {
|
||||||
const text = content.toString('utf8');
|
const text = content.toString('utf8');
|
||||||
const minified = uglify.minify(text);
|
const minified = Terser.minify(text);
|
||||||
return (minified && minified.code) ? Buffer.from(minified.code) : content;
|
return (minified && minified.code) ? Buffer.from(minified.code) : content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,21 +66,4 @@ const config = module.exports = merge(common, {
|
||||||
path: path.resolve(__dirname, 'dist/clips'),
|
path: path.resolve(__dirname, 'dist/clips'),
|
||||||
filename: '[name].[hash].js'
|
filename: '[name].[hash].js'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// This is why we can't have nice things.
|
|
||||||
// Why can't I just access process.env.NODE_ENV from
|
|
||||||
// one of these files when I set it with webpack's
|
|
||||||
// CLI? So stupid.
|
|
||||||
//
|
|
||||||
// So here we go.
|
|
||||||
// This is crap.
|
|
||||||
// But it works.
|
|
||||||
|
|
||||||
for(const rule of config.module.rules) {
|
|
||||||
if ( Array.isArray(rule.use) )
|
|
||||||
for(const use of rule.use)
|
|
||||||
if ( use.options && use.options.name && use.options.name.startsWith('[name].') )
|
|
||||||
use.options.name = `[name].[hash].${use.options.name.slice(7)}`;
|
|
||||||
}
|
|
|
@ -1,7 +1,11 @@
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
/* global module __dirname */
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
|
/* global process module __dirname */
|
||||||
|
|
||||||
|
const PRODUCTION = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
|
@ -30,7 +34,15 @@ module.exports = {
|
||||||
jsonpFunction: 'ffzWebpackJsonp',
|
jsonpFunction: 'ffzWebpackJsonp',
|
||||||
crossOriginLoading: 'anonymous'
|
crossOriginLoading: 'anonymous'
|
||||||
},
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
vendors: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new VueLoaderPlugin(),
|
||||||
new webpack.ExtendedAPIPlugin()
|
new webpack.ExtendedAPIPlugin()
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
|
@ -39,7 +51,7 @@ module.exports = {
|
||||||
use: [{
|
use: [{
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
name: '[name].css'
|
name: PRODUCTION ? '[name].[hash].css' : '[name].css'
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
loader: 'extract-loader'
|
loader: 'extract-loader'
|
||||||
|
@ -55,10 +67,35 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.json$/,
|
||||||
|
include: /src/,
|
||||||
|
type: 'javascript/auto',
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: PRODUCTION ? '[name].[hash].json' : '[name].json'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
cacheDirectory: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.jsx$/,
|
test: /\.jsx$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader'
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
cacheDirectory: true,
|
||||||
|
plugins: [
|
||||||
|
['@babel/plugin-transform-react-jsx', {
|
||||||
|
pragma: 'createElement'
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(graphql|gql)$/,
|
test: /\.(graphql|gql)$/,
|
||||||
|
@ -70,7 +107,7 @@ module.exports = {
|
||||||
use: [{
|
use: [{
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
name: '[name].[ext]'
|
name: PRODUCTION ? '[name].[hash].[ext]' : '[name].[ext]'
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
const webpack = require('webpack');
|
|
||||||
const merge = require('webpack-merge');
|
|
||||||
const common = require('./webpack.web.common.js');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const CleanPlugin = require('clean-webpack-plugin');
|
|
||||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
|
||||||
|
|
||||||
const commit_hash = require('child_process').execSync('git rev-parse HEAD').toString().trim();
|
|
||||||
|
|
||||||
/* global module __dirname */
|
|
||||||
|
|
||||||
const config = module.exports = merge(common, {
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
plugins: ['transform-es2015-classes']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new CleanPlugin(['dist/babel']),
|
|
||||||
new UglifyJSPlugin({
|
|
||||||
sourceMap: true,
|
|
||||||
uglifyOptions: {
|
|
||||||
compress: {
|
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
keep_classnames: true,
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__git_commit__: JSON.stringify(commit_hash)
|
|
||||||
}),
|
|
||||||
new ManifestPlugin({
|
|
||||||
basePath: 'babel/',
|
|
||||||
publicPath: 'babel/',
|
|
||||||
map: data => {
|
|
||||||
if ( data.name.endsWith('.scss') )
|
|
||||||
data.name = `${data.name.substr(0,data.name.length - 5)}.css`;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
output: {
|
|
||||||
publicPath: '//cdn.frankerfacez.com/static/babel/',
|
|
||||||
path: path.resolve(__dirname, 'dist/babel'),
|
|
||||||
filename: '[name].[hash].js'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// This is why we can't have nice things.
|
|
||||||
// Why can't I just access process.env.NODE_ENV from
|
|
||||||
// one of these files when I set it with webpack's
|
|
||||||
// CLI? So stupid.
|
|
||||||
//
|
|
||||||
// So here we go.
|
|
||||||
// This is crap.
|
|
||||||
// But it works.
|
|
||||||
|
|
||||||
for(const rule of config.module.rules) {
|
|
||||||
if ( Array.isArray(rule.use) )
|
|
||||||
for(const use of rule.use)
|
|
||||||
if ( use.options && use.options.name && use.options.name.startsWith('[name].') )
|
|
||||||
use.options.name = `[name].[hash].${use.options.name.slice(7)}`;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
const path = require('path');
|
|
||||||
const merge = require('webpack-merge');
|
|
||||||
const dev = require('./webpack.web.dev.js');
|
|
||||||
|
|
||||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
|
|
||||||
/* global module */
|
|
||||||
|
|
||||||
module.exports = merge(dev, {
|
|
||||||
module: {
|
|
||||||
rules: [{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true,
|
|
||||||
plugins: ['transform-es2015-classes']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new UglifyJSPlugin({
|
|
||||||
sourceMap: true,
|
|
||||||
uglifyOptions: {
|
|
||||||
compress: {
|
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
keep_classnames: true,
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
|
@ -9,6 +9,7 @@ const webpack = require('webpack');
|
||||||
/* global module */
|
/* global module */
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -39,7 +40,7 @@ module.exports = merge(common, {
|
||||||
|
|
||||||
proxy: {
|
proxy: {
|
||||||
'**': {
|
'**': {
|
||||||
target: 'http://cdn.frankerfacez.com/',
|
target: 'https://cdn.frankerfacez.com/',
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -63,6 +64,7 @@ module.exports = merge(common, {
|
||||||
output: {
|
output: {
|
||||||
publicPath: '//localhost:8000/script/',
|
publicPath: '//localhost:8000/script/',
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
jsonpFunction: 'ffzWebpackJsonp'
|
jsonpFunction: 'ffzWebpackJsonp',
|
||||||
|
crossOriginLoading: 'anonymous'
|
||||||
}
|
}
|
||||||
})
|
})
|
67
webpack.web.dev.prod.js
Normal file
67
webpack.web.dev.prod.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
const path = require('path');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
|
const prod = require('./webpack.web.prod.js');
|
||||||
|
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
/* global module */
|
||||||
|
|
||||||
|
module.exports = merge(prod, {
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin([
|
||||||
|
{
|
||||||
|
from: './src/entry.js',
|
||||||
|
to: 'script.js'
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
__git_commit__: null
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
https: true,
|
||||||
|
port: 8000,
|
||||||
|
compress: true,
|
||||||
|
inline: false,
|
||||||
|
|
||||||
|
allowedHosts: [
|
||||||
|
'.twitch.tv',
|
||||||
|
'.frankerfacez.com'
|
||||||
|
],
|
||||||
|
|
||||||
|
contentBase: path.join(__dirname, 'dev_cdn'),
|
||||||
|
publicPath: '/script/',
|
||||||
|
|
||||||
|
proxy: {
|
||||||
|
'**': {
|
||||||
|
target: 'https://cdn.frankerfacez.com/',
|
||||||
|
changeOrigin: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
before(app) {
|
||||||
|
// Because the headers config option is broken.
|
||||||
|
app.get('/*', (req, res, next) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/dev_server', (req, res) => {
|
||||||
|
res.json({
|
||||||
|
path: process.cwd(),
|
||||||
|
version: 2
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
publicPath: '//localhost:8000/script/',
|
||||||
|
filename: '[name].js',
|
||||||
|
jsonpFunction: 'ffzWebpackJsonp',
|
||||||
|
crossOriginLoading: 'anonymous'
|
||||||
|
}
|
||||||
|
})
|
|
@ -3,11 +3,11 @@ const merge = require('webpack-merge');
|
||||||
const common = require('./webpack.web.common.js');
|
const common = require('./webpack.web.common.js');
|
||||||
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||||
const CleanPlugin = require('clean-webpack-plugin');
|
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
||||||
|
|
||||||
const uglify = require('uglify-es');
|
const Terser = require('terser');
|
||||||
|
|
||||||
// Get Git info
|
// Get Git info
|
||||||
|
|
||||||
|
@ -15,24 +15,25 @@ const commit_hash = require('child_process').execSync('git rev-parse HEAD').toSt
|
||||||
|
|
||||||
/* global module Buffer */
|
/* global module Buffer */
|
||||||
|
|
||||||
const config = module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
|
mode: 'production',
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
|
|
||||||
plugins: [
|
optimization: {
|
||||||
new CleanPlugin(['dist']),
|
concatenateModules: false,
|
||||||
new UglifyJSPlugin({
|
minimizer: [
|
||||||
sourceMap: true,
|
new TerserPlugin({
|
||||||
uglifyOptions: {
|
sourceMap: true,
|
||||||
compress: {
|
terserOptions: {
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
keep_classnames: true,
|
keep_classnames: true,
|
||||||
keep_fnames: true
|
keep_fnames: true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}),
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
__git_commit__: JSON.stringify(commit_hash)
|
__git_commit__: JSON.stringify(commit_hash)
|
||||||
}),
|
}),
|
||||||
|
@ -42,7 +43,7 @@ const config = module.exports = merge(common, {
|
||||||
to: 'script.min.js',
|
to: 'script.min.js',
|
||||||
transform: content => {
|
transform: content => {
|
||||||
const text = content.toString('utf8');
|
const text = content.toString('utf8');
|
||||||
const minified = uglify.minify(text);
|
const minified = Terser.minify(text);
|
||||||
return (minified && minified.code) ? Buffer.from(minified.code) : content;
|
return (minified && minified.code) ? Buffer.from(minified.code) : content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,21 +62,4 @@ const config = module.exports = merge(common, {
|
||||||
publicPath: '//cdn.frankerfacez.com/static/',
|
publicPath: '//cdn.frankerfacez.com/static/',
|
||||||
filename: '[name].[hash].js'
|
filename: '[name].[hash].js'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// This is why we can't have nice things.
|
|
||||||
// Why can't I just access process.env.NODE_ENV from
|
|
||||||
// one of these files when I set it with webpack's
|
|
||||||
// CLI? So stupid.
|
|
||||||
//
|
|
||||||
// So here we go.
|
|
||||||
// This is crap.
|
|
||||||
// But it works.
|
|
||||||
|
|
||||||
for(const rule of config.module.rules) {
|
|
||||||
if ( Array.isArray(rule.use) )
|
|
||||||
for(const use of rule.use)
|
|
||||||
if ( use.options && use.options.name && use.options.name.startsWith('[name].') )
|
|
||||||
use.options.name = `[name].[hash].${use.options.name.slice(7)}`;
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue