From d5ed46150e2f84ce8c5e786aceccb4374c84079d Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Tue, 31 Mar 2020 15:19:53 +0200 Subject: [PATCH] Added tr caching to webpack --- package-lock.json | 6 ++ package.json | 14 ++-- shared/js/ConnectionHandler.ts | 2 +- shared/js/i18n/localize.ts | 2 +- shared/js/main.ts | 6 +- shared/js/profiles/identities/NameIdentity.ts | 1 - shared/js/ui/modal/ModalNewcomer.ts | 18 ++--- .../modal/permission/ModalPermissionEdit.ts | 3 +- tools/trgen/compiler.ts | 1 - tools/trgen/generator.ts | 1 - tools/trgen/index.ts | 2 - tools/trgen/ts_generator.ts | 48 +++++++------ tools/trgen/ts_transformer.ts | 67 ++++++++++++++++++ tools/trgen/ttsc_transformer.ts | 68 ++----------------- tools/trmanager/.gitignore | 2 - tools/trmanager/index.html | 10 --- webpack.config.js => webpack.config.ts | 38 ++++++++--- webpack/WatLoader.ts | 8 +-- 18 files changed, 160 insertions(+), 137 deletions(-) create mode 100644 tools/trgen/ts_transformer.ts delete mode 100644 tools/trmanager/.gitignore delete mode 100644 tools/trmanager/index.html rename webpack.config.js => webpack.config.ts (69%) diff --git a/package-lock.json b/package-lock.json index 947f5178..edf9fd4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9240,6 +9240,12 @@ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true }, + "wabt": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/wabt/-/wabt-1.0.13.tgz", + "integrity": "sha512-nkWPyUjYt+SqPox2mjJF5jrpWv30awdXKdG0OmryzfhtahHBrPz/BGSbakPgcJU2SFjC1s7Mb8MadRhQ6lmqUg==", + "dev": true + }, "watchpack": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", diff --git a/package.json b/package.json index 61c8b1e8..7b3a1823 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "author": "TeaSpeak (WolverinDEV)", "license": "ISC", "devDependencies": { - "@types/fs-extra": "^8.0.1", "@types/emscripten": "^1.38.0", + "@types/fs-extra": "^8.0.1", "@types/jquery": "^3.3.34", "@types/lodash": "^4.14.149", "@types/moment": "^2.13.0", @@ -36,12 +36,15 @@ "@types/sha256": "^0.2.0", "@types/websocket": "0.0.40", "chunk-manifest-webpack-plugin": "^1.1.2", + "circular-dependency-plugin": "^5.2.0", "clean-css": "^4.2.1", "clean-webpack-plugin": "^3.0.0", + "css-loader": "^3.4.2", "csso-cli": "^2.0.2", "exports-loader": "^0.7.0", "fs-extra": "latest", "gulp": "^4.0.2", + "html-loader": "^1.0.0", "html-webpack-plugin": "^4.0.3", "mime-types": "^2.1.24", "mini-css-extract-plugin": "^0.9.0", @@ -49,20 +52,19 @@ "node-sass": "^4.13.1", "raw-loader": "^4.0.0", "sass": "1.22.10", + "sass-loader": "^8.0.2", "sha256": "^0.2.0", + "style-loader": "^1.1.3", "terser": "^4.2.1", "ts-loader": "^6.2.2", "ttypescript": "^1.5.10", "typescript": "3.6.5", + "wabt": "^1.0.13", "webpack": "^4.42.1", "webpack-bundle-analyzer": "^3.6.1", "webpack-cli": "^3.3.11", "worker-plugin": "^4.0.2", - "circular-dependency-plugin": "^5.2.0", - "css-loader": "^3.4.2", - "html-loader": "^1.0.0", - "sass-loader": "^8.0.2", - "style-loader": "^1.1.3" + "terser-webpack-plugin": "latest" }, "repository": { "type": "git", diff --git a/shared/js/ConnectionHandler.ts b/shared/js/ConnectionHandler.ts index 8a0b6731..3cec06c1 100644 --- a/shared/js/ConnectionHandler.ts +++ b/shared/js/ConnectionHandler.ts @@ -477,7 +477,7 @@ export class ConnectionHandler { this._certificate_modal = createErrorModal( tr("Could not connect"), - formatMessage(tr(error_message_format), this.generate_ssl_certificate_accept()) + formatMessage(/* @tr-ignore */ tr(error_message_format), this.generate_ssl_certificate_accept()) ); this._certificate_modal.close_listener.push(() => this._certificate_modal = undefined); this._certificate_modal.open(); diff --git a/shared/js/i18n/localize.ts b/shared/js/i18n/localize.ts index 11ca2368..48602847 100644 --- a/shared/js/i18n/localize.ts +++ b/shared/js/i18n/localize.ts @@ -70,7 +70,7 @@ export function tr(message: string, key?: string) { } export function tra(message: string, ...args: any[]) { - message = tr(message); + message = /* @tr-ignore */ tr(message); return formatMessage(message, ...args); } diff --git a/shared/js/main.ts b/shared/js/main.ts index 2c0b1121..3c4956c5 100644 --- a/shared/js/main.ts +++ b/shared/js/main.ts @@ -113,7 +113,7 @@ function setup_jsrender() : boolean { }); js_render.views.tags("tr", (...args) => { - return tr(args[0]); + return /* @tr-ignore */ tr(args[0]); }); $(".jsrender-template").each((idx, _entry) => { @@ -481,7 +481,7 @@ const task_connect_handler: loader.Task = { "You could now close this page."; createInfoModal( tr("Connecting successfully within other instance"), - formatMessage(tr(message), connect_data.address), + formatMessage(/* @tr-ignore */ tr(message), connect_data.address), { closeable: false, footer: undefined @@ -548,7 +548,7 @@ const task_certificate_callback: loader.Task = { "This page will close in {0} seconds."; createInfoModal( tr("Certificate acccepted successfully"), - formatMessage(tr(message), seconds_tag), + formatMessage(/* @tr-ignore */ tr(message), seconds_tag), { closeable: false, footer: undefined diff --git a/shared/js/profiles/identities/NameIdentity.ts b/shared/js/profiles/identities/NameIdentity.ts index c0a14aa2..c3d65831 100644 --- a/shared/js/profiles/identities/NameIdentity.ts +++ b/shared/js/profiles/identities/NameIdentity.ts @@ -10,7 +10,6 @@ import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration"; import {AbstractServerConnection} from "tc-shared/connection/ConnectionBase"; import {HandshakeIdentityHandler} from "tc-shared/connection/HandshakeHandler"; -console.error(AbstractHandshakeIdentityHandler); class NameHandshakeHandler extends AbstractHandshakeIdentityHandler { readonly identity: NameIdentity; handler: HandshakeCommandHandler; diff --git a/shared/js/ui/modal/ModalNewcomer.ts b/shared/js/ui/modal/ModalNewcomer.ts index b537573c..2a93ac9d 100644 --- a/shared/js/ui/modal/ModalNewcomer.ts +++ b/shared/js/ui/modal/ModalNewcomer.ts @@ -163,7 +163,7 @@ function initializeStepIdentity(tag: JQuery, event_registry: Registry" + "press a key. The key could be selected " + "via the button right to the radio button." @@ -401,7 +401,7 @@ function initializeStepMicrophone(tag: JQuery, event_registry: Registry { @@ -1358,7 +1359,7 @@ function apply_server_groups(connection: ConnectionHandler, editor: AbstractPerm console.log(tr("Failed to add client %o to server group %o: %o"), dbid, current_group.id, error); if(error instanceof CommandResult) error = error.extra_message || error.message; - createErrorModal(tr("Failed to add client"), tr("Failed to add client to server group\n" + error)).open(); + createErrorModal(tr("Failed to add client"), tra("Failed to add client to server group{:br:}", error)).open(); }); }).open(); }); diff --git a/tools/trgen/compiler.ts b/tools/trgen/compiler.ts index efafcc82..ef2f438f 100644 --- a/tools/trgen/compiler.ts +++ b/tools/trgen/compiler.ts @@ -49,7 +49,6 @@ function compile(fileNames: string[], options: ts.CompilerOptions): void { } const config = ts.parseCommandLine(process.argv.slice(2), file => readFileSync(file).toString()); -console.dir(config); if(config.errors && config.errors.length > 0) { for(const error of config.errors) console.log(error.messageText); diff --git a/tools/trgen/generator.ts b/tools/trgen/generator.ts index 99408f2a..71cab0b7 100644 --- a/tools/trgen/generator.ts +++ b/tools/trgen/generator.ts @@ -1,4 +1,3 @@ - export interface TranslationEntry { filename: string; line: number; diff --git a/tools/trgen/index.ts b/tools/trgen/index.ts index 22dd2784..db395c99 100644 --- a/tools/trgen/index.ts +++ b/tools/trgen/index.ts @@ -8,8 +8,6 @@ import {isArray} from "util"; import * as mkdirp from "mkdirp"; import {TranslationEntry} from "./generator"; -console.log("TR GEN!"); - /* const files = ["/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/build/trgen/test/test_01.ts"]; files.forEach(file => { diff --git a/tools/trgen/ts_generator.ts b/tools/trgen/ts_generator.ts index 02097924..4ee1f70e 100644 --- a/tools/trgen/ts_generator.ts +++ b/tools/trgen/ts_generator.ts @@ -11,10 +11,14 @@ export function generate(file: ts.SourceFile, config: Configuration) : Translati return result; } -function report(node: ts.Node, message: string) { +const source_location = (node: ts.Node) => { const sf = node.getSourceFile(); let { line, character } = sf ? sf.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; - console.log(`${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1}): ${message}`); + return `${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1})`; +}; + +function report(node: ts.Node, message: string) { + console.log(`${source_location(node)}: ${message}`); } function _generate(config: Configuration, node: ts.Node, result: TranslationEntry[]) { @@ -27,7 +31,6 @@ function _generate(config: Configuration, node: ts.Node, result: TranslationEntr if(call_name != "tr") break call_analize; console.dir(call_name); - console.log("Parameters: %o", call.arguments.length); if(call.arguments.length > 1) { report(call, "Invalid argument count"); @@ -159,7 +162,7 @@ function create_unique_check(source_file: ts.SourceFile, variable: ts.Expression return [...nodes, ts.createLabel(unique_check_label_name, ts.createBlock(blocked_nodes))]; } -export function transform(config: Configuration, context: ts.TransformationContext, node: ts.SourceFile) : TransformResult { +export function transform(config: Configuration, context: ts.TransformationContext, source_file: ts.SourceFile) : TransformResult { const cache: VolatileTransformConfig = {} as any; cache.translations = []; @@ -215,56 +218,59 @@ export function transform(config: Configuration, context: ts.TransformationConte function visit(node: ts.Node): ts.Node { node = ts.visitEachChild(node, visit, context); - return replace_processor(config, cache, node); + return replace_processor(config, cache, node, source_file); } - node = ts.visitNode(node, visit); - extra_nodes.push(...create_unique_check(node, cache.nodes.translation_map_init, generated_names)); + source_file = ts.visitNode(source_file, visit); + extra_nodes.push(...create_unique_check(source_file, cache.nodes.translation_map_init, generated_names)); - node = ts.updateSourceFileNode(node, [...(extra_nodes as any[]), ...node.statements], node.isDeclarationFile, node.referencedFiles, node.typeReferenceDirectives, node.hasNoDefaultLib, node.referencedFiles); + source_file = ts.updateSourceFileNode(source_file, [...(extra_nodes as any[]), ...source_file.statements], source_file.isDeclarationFile, source_file.referencedFiles, source_file.typeReferenceDirectives, source_file.hasNoDefaultLib, source_file.referencedFiles); const result: TransformResult = {} as any; - result.node = node; + result.node = source_file; result.translations = cache.translations; return result; } -export function replace_processor(config: Configuration, cache: VolatileTransformConfig, node: ts.Node) : ts.Node { +export function replace_processor(config: Configuration, cache: VolatileTransformConfig, node: ts.Node, source_file: ts.SourceFile) : ts.Node { if(config.verbose) console.log("Process %s", SyntaxKind[node.kind]); if(ts.isCallExpression(node)) { const call = node; const call_name = call.expression["escapedText"] as string; if(call_name != "tr") return node; - + if(!node.getSourceFile()) return node; if(config.verbose) { console.dir(call_name); console.log("Parameters: %o", call.arguments.length); } - if(call.arguments.length > 1) { - report(call, "Invalid argument count"); + + if(call.arguments.length > 1) + throw new Error(source_location(call) + ": tr(...) has been called with an invalid arguments (" + (call.arguments.length === 0 ? "too few" : "too many") + ")"); + + const fullText = call.getFullText(source_file); + if(fullText && fullText.indexOf("@tr-ignore") !== -1) return node; - } const object = call.arguments[0]; if(object.kind != SyntaxKind.StringLiteral) { - report(call, "Invalid argument: " + SyntaxKind[object.kind]); - return node; + if(call.getSourceFile()) + throw new Error(source_location(call) + ": Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); + report(call, "Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); } if(config.verbose) - console.log("Message: %o", object.text || object.getText()); + console.log("Message: %o", object.text || object.getText(source_file)); - const variable_name = ts.createIdentifier(cache.name_generator(config, node, object.text || object.getText())); + const variable_name = ts.createIdentifier(cache.name_generator(config, node, object.text || object.getText(source_file))); const variable_init = ts.createPropertyAccess(cache.nodes.translation_map_init, variable_name); const variable = ts.createPropertyAccess(cache.nodes.translation_map, variable_name); const new_variable = ts.createAssignment(variable, call); - const source_file = node.getSourceFile(); - let { line, character } = source_file ? source_file.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; + let { line, character } = source_file.getLineAndCharacterOfPosition(node.getStart()); cache.translations.push({ - message: object.text || object.getText(), + message: object.text || object.getText(source_file), line: line, character: character, filename: (source_file || {fileName: "unknown"}).fileName diff --git a/tools/trgen/ts_transformer.ts b/tools/trgen/ts_transformer.ts new file mode 100644 index 00000000..d5a7bae6 --- /dev/null +++ b/tools/trgen/ts_transformer.ts @@ -0,0 +1,67 @@ +import * as ts from "typescript"; +import * as ts_generator from "./ts_generator"; +import * as path from "path"; +import * as mkdirp from "mkdirp"; + +import {writeFileSync} from "fs"; +import {TranslationEntry} from "./generator"; + +export interface Config { + target_file?: string; + verbose?: boolean; +} + +let process_config: Config; +export default function(program: ts.Program, config?: Config) : (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile { + process_config = config as any || {}; + + const base_path = path.dirname(program.getCompilerOptions().project || program.getCurrentDirectory()); + if(process_config.verbose) { + console.log("TRGen transformer called"); + console.log("Base path: %s", base_path); + } + + process.on('exit', function () { + if(!process_config.target_file) return; + + const target = path.isAbsolute(process_config.target_file) ? process_config.target_file : path.join(base_path, process_config.target_file); + if(process_config.target_file) { + if(process_config.verbose) + console.log("Writing translation file to " + target); + + mkdirp.sync(path.dirname(target)); + writeFileSync(target, JSON.stringify(translations, null, 2)); + } + }); + + return ctx => transformer(ctx) as any; +} + +const translations: TranslationEntry[] = []; +const transformer = (context: ts.TransformationContext) => +(rootNode: ts.Node) => { + const handler = (rootNode: ts.Node) => { + if(rootNode.kind == ts.SyntaxKind.Bundle) { + const bundle = rootNode as ts.Bundle; + const result = []; + for(const file of bundle.sourceFiles) + result.push(handler(file)); + return ts.updateBundle(bundle, result as any, bundle.prepends as any); + + } else if(rootNode.kind == ts.SyntaxKind.SourceFile) { + const file = rootNode as ts.SourceFile; + + console.log("Processing " + file.fileName); + const result = ts_generator.transform({ + use_window: false, + replace_cache: true + }, context, file); + translations.push(...result.translations); + return result.node; + } else { + console.warn("Invalid transform input: %s", ts.SyntaxKind[rootNode.kind]); + } + }; + + return handler(rootNode); +}; \ No newline at end of file diff --git a/tools/trgen/ttsc_transformer.ts b/tools/trgen/ttsc_transformer.ts index 7bc58503..4885dd05 100644 --- a/tools/trgen/ttsc_transformer.ts +++ b/tools/trgen/ttsc_transformer.ts @@ -1,67 +1,9 @@ -import * as ts from "typescript"; -import * as ts_generator from "./ts_generator"; -import * as path from "path"; -import * as mkdirp from "mkdirp"; - +import transform, {Config} from "./ts_transformer"; import {PluginConfig} from "ttypescript/lib/PluginCreator"; -import {writeFileSync} from "fs"; -import {TranslationEntry} from "./generator"; +import * as ts from "typescript"; -interface Config { - target_file?: string; - verbose?: boolean; -} - -//(program: ts.Program, config?: PluginConfig) => ts.TransformerFactory -let process_config: Config; export default function(program: ts.Program, config?: PluginConfig) : (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile { - process_config = config as any || {}; + const process_config: Config = config as any || {}; - const base_path = path.dirname(program.getCompilerOptions().project || program.getCurrentDirectory()); - if(process_config.verbose) { - console.log("TRGen transformer called"); - console.log("Base path: %s", base_path); - } - - process.on('exit', function () { - const target = path.isAbsolute(process_config.target_file) ? process_config.target_file : path.join(base_path, process_config.target_file); - if(process_config.target_file) { - if(process_config.verbose) - console.log("Writing translation file to " + target); - - mkdirp.sync(path.dirname(target)); - writeFileSync(target, JSON.stringify(translations, null, 2)); - } - }); - - return ctx => transformer(ctx) as any; -} - -const translations: TranslationEntry[] = []; -const transformer = (context: ts.TransformationContext) => -(rootNode: ts.Node) => { - const handler = (rootNode: ts.Node) => { - if(rootNode.kind == ts.SyntaxKind.Bundle) { - const bundle = rootNode as ts.Bundle; - const result = []; - for(const file of bundle.sourceFiles) - result.push(handler(file)); - return ts.updateBundle(bundle, result as any, bundle.prepends as any); - - } else if(rootNode.kind == ts.SyntaxKind.SourceFile) { - const file = rootNode as ts.SourceFile; - - console.log("Processing " + file.fileName); - const result = ts_generator.transform({ - use_window: false, - replace_cache: true - }, context, file); - translations.push(...result.translations); - return result.node; - } else { - console.warn("Invalid transform input: %s", ts.SyntaxKind[rootNode.kind]); - } - }; - - return handler(rootNode); -}; \ No newline at end of file + return transform(program, process_config); +} \ No newline at end of file diff --git a/tools/trmanager/.gitignore b/tools/trmanager/.gitignore deleted file mode 100644 index 20efd1ec..00000000 --- a/tools/trmanager/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -**/*.js -**/*.js.map \ No newline at end of file diff --git a/tools/trmanager/index.html b/tools/trmanager/index.html deleted file mode 100644 index ebc0c722..00000000 --- a/tools/trmanager/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Translation Manager - - -
This needs some improvements
- - \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.ts similarity index 69% rename from webpack.config.js rename to webpack.config.ts index 60c2e8d9..412ca812 100644 --- a/webpack.config.js +++ b/webpack.config.ts @@ -1,19 +1,23 @@ +import * as ts from "typescript"; +import trtransformer, {Config} from "./tools/trgen/ts_transformer"; + const path = require('path'); const webpack = require("webpack"); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const ManifestGenerator = require("./webpack/ManifestPlugin"); const WorkerPlugin = require('worker-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const isDevelopment = process.env.NODE_ENV === 'development'; +let isDevelopment = process.env.NODE_ENV === 'development'; +isDevelopment = true; module.exports = { entry: { - //"shared-app": "./shared/js/main.ts" "shared-app": "./web/js/index.ts" }, - devtool: 'inline-source-map', - mode: "development", + devtool: isDevelopment ? "inline-source-map" : undefined, + mode: isDevelopment ? "development" : "production", plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ @@ -34,8 +38,8 @@ module.exports = { }) */ new webpack.optimize.AggressiveSplittingPlugin({ - minSize: 1024 * 128, - maxSize: 1024 * 1024 + minSize: 1024 * 8, + maxSize: 1024 * 128 }) ], module: { @@ -43,8 +47,7 @@ module.exports = { { test: /\.s[ac]ss$/, loader: [ - //isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, - 'style-loader', + isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { @@ -68,8 +71,21 @@ module.exports = { { loader: 'ts-loader', options: { - transpileOnly: true + transpileOnly: true, + getCustomTransformers: (prog: ts.Program) => { + return { + before: [trtransformer(prog, {})] + }; + } } + /* + { + "transform": "../../tools/trgen/ttsc_transformer.js", + "type": "program", + "target_file": "../generated/messages_script.json", + "verbose": true + } + */ } ] }, @@ -100,6 +116,8 @@ module.exports = { publicPath: "js/" }, optimization: { - splitChunks: { } + splitChunks: { }, + minimize: !isDevelopment, + minimizer: [new TerserPlugin()] } }; \ No newline at end of file diff --git a/webpack/WatLoader.ts b/webpack/WatLoader.ts index f1c8b982..7597d523 100644 --- a/webpack/WatLoader.ts +++ b/webpack/WatLoader.ts @@ -2,7 +2,7 @@ import * as webpack from "webpack"; import {RawSourceMap} from "source-map"; import LoaderContext = webpack.loader.LoaderContext; -const wabt = require("wabt"); +const wabt = require("wabt")(); const filename = "module.wast"; @@ -10,9 +10,7 @@ export default function loader(this: LoaderContext, source: string | Buffer, sou this.cacheable(); const module = wabt.parseWat(filename, source); - const { buffer } = module.toBinary({ write_debug_names: true, relocatable: true, canonicalize_lebs: true, log: true }); + const { buffer } = module.toBinary({ write_debug_names: false }); - this.emitFile("test.wasm", buffer, null); - const result = `module.exports = new Uint8Array([${buffer.join(",")}]);`; - this.callback(null, result); + this.callback(null, `module.exports = new Uint8Array([${buffer.join(",")}]);`); } \ No newline at end of file