Improved the webpack script and using constants for build version detection
parent
b297147f98
commit
c460d05ee5
11
file.ts
11
file.ts
|
@ -37,8 +37,6 @@ const APP_FILE_LIST_SHARED_SOURCE: ProjectResource[] = [
|
||||||
"path": "./",
|
"path": "./",
|
||||||
"local-path": "./shared/html/"
|
"local-path": "./shared/html/"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
{ /* javascript files as manifest.json */
|
{ /* javascript files as manifest.json */
|
||||||
"type": "js",
|
"type": "js",
|
||||||
"search-pattern": /.*$/,
|
"search-pattern": /.*$/,
|
||||||
|
@ -47,15 +45,6 @@ const APP_FILE_LIST_SHARED_SOURCE: ProjectResource[] = [
|
||||||
"path": "js/",
|
"path": "js/",
|
||||||
"local-path": "./dist/"
|
"local-path": "./dist/"
|
||||||
},
|
},
|
||||||
{ /* loader javascript file */
|
|
||||||
"type": "js",
|
|
||||||
"search-pattern": /.*$/,
|
|
||||||
"build-target": "dev|rel",
|
|
||||||
|
|
||||||
"path": "js/",
|
|
||||||
"local-path": "./loader/dist/"
|
|
||||||
},
|
|
||||||
|
|
||||||
{ /* shared developer single css files */
|
{ /* shared developer single css files */
|
||||||
"type": "css",
|
"type": "css",
|
||||||
"search-pattern": /.*\.css$/,
|
"search-pattern": /.*\.css$/,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import * as loader from "./targets/app";
|
import * as loader from "./targets/app";
|
||||||
import * as loader_base from "./loader/loader";
|
import * as loader_base from "./loader/loader";
|
||||||
|
|
||||||
export = loader_base;
|
window["loader"] = loader_base;
|
||||||
/* let the loader register himself at the window first */
|
/* let the loader register himself at the window first */
|
||||||
setTimeout(loader.run, 0);
|
setTimeout(loader.run, 0);
|
||||||
|
|
||||||
|
export {};
|
|
@ -1,5 +1,3 @@
|
||||||
import {AppVersion} from "tc-loader";
|
|
||||||
import {LoadSyntaxError, script_name} from "./utils";
|
|
||||||
import * as script_loader from "./script_loader";
|
import * as script_loader from "./script_loader";
|
||||||
import * as style_loader from "./style_loader";
|
import * as style_loader from "./style_loader";
|
||||||
import * as template_loader from "./template_loader";
|
import * as template_loader from "./template_loader";
|
||||||
|
@ -75,38 +73,35 @@ const tasks: {[key:number]:Task[]} = {};
|
||||||
|
|
||||||
/* test if all files shall be load from cache or fetch again */
|
/* test if all files shall be load from cache or fetch again */
|
||||||
function loader_cache_tag() {
|
function loader_cache_tag() {
|
||||||
const app_version = (() => {
|
if(__build.mode === "debug") {
|
||||||
const version_node = document.getElementById("app_version");
|
|
||||||
if(!version_node) return undefined;
|
|
||||||
|
|
||||||
const version = version_node.hasAttribute("value") ? version_node.getAttribute("value") : undefined;
|
|
||||||
if(!version) return undefined;
|
|
||||||
|
|
||||||
if(!version || version == "unknown" || version.replace(/0+/, "").length == 0)
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
return version;
|
|
||||||
})();
|
|
||||||
if(config.verbose) console.log("Found current app version: %o", app_version);
|
|
||||||
|
|
||||||
if(!app_version) {
|
|
||||||
/* TODO add warning */
|
|
||||||
cache_tag = "?_ts=" + Date.now();
|
cache_tag = "?_ts=" + Date.now();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cached_version = localStorage.getItem("cached_version");
|
const cached_version = localStorage.getItem("cached_version");
|
||||||
if(!cached_version || cached_version != app_version) {
|
if(!cached_version || cached_version !== __build.version) {
|
||||||
register_task(Stage.LOADED, {
|
register_task(Stage.LOADED, {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
name: "cached version updater",
|
name: "cached version updater",
|
||||||
function: async () => {
|
function: async () => {
|
||||||
localStorage.setItem("cached_version", app_version);
|
localStorage.setItem("cached_version", __build.version);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
cache_tag = "?_version=" + app_version;
|
cache_tag = "?_version=" + __build.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ModuleMapping = {
|
||||||
|
application: string,
|
||||||
|
modules: {
|
||||||
|
"id": string,
|
||||||
|
"context": string,
|
||||||
|
"resource": string
|
||||||
|
}[]
|
||||||
|
};
|
||||||
|
const module_mapping_: ModuleMapping[] = [];
|
||||||
|
export function module_mapping() : ModuleMapping[] { return module_mapping_; }
|
||||||
|
|
||||||
export function get_cache_version() { return cache_tag; }
|
export function get_cache_version() { return cache_tag; }
|
||||||
|
|
||||||
export function finished() {
|
export function finished() {
|
||||||
|
@ -259,12 +254,6 @@ export function hide_overlay() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* versions management */
|
|
||||||
let version_: AppVersion;
|
|
||||||
export function version() : AppVersion { return version_; }
|
|
||||||
export function set_version(version: AppVersion) { version_ = version; }
|
|
||||||
|
|
||||||
|
|
||||||
/* critical error handler */
|
/* critical error handler */
|
||||||
export type ErrorHandler = (message: string, detail: string) => void;
|
export type ErrorHandler = (message: string, detail: string) => void;
|
||||||
let _callback_critical_error: ErrorHandler;
|
let _callback_critical_error: ErrorHandler;
|
||||||
|
|
|
@ -31,38 +31,20 @@ interface Manifest {
|
||||||
version: number;
|
version: number;
|
||||||
|
|
||||||
chunks: {[key: string]: {
|
chunks: {[key: string]: {
|
||||||
hash: string,
|
files: {
|
||||||
file: string
|
hash: string,
|
||||||
}[]};
|
file: string
|
||||||
}
|
}[],
|
||||||
|
modules: {
|
||||||
interface BuildDefinitions {
|
id: string,
|
||||||
development: boolean,
|
context: string,
|
||||||
version: string
|
resource: string
|
||||||
}
|
}[]
|
||||||
declare global {
|
}};
|
||||||
const __build: BuildDefinitions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all javascript loaders */
|
/* all javascript loaders */
|
||||||
const loader_javascript = {
|
const loader_javascript = {
|
||||||
detect_type: async () => {
|
|
||||||
if(window.native_client) {
|
|
||||||
loader.set_version({
|
|
||||||
backend: "-",
|
|
||||||
ui: ui_version(),
|
|
||||||
debug_mode: __build.development,
|
|
||||||
type: "native"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
loader.set_version({
|
|
||||||
backend: "-",
|
|
||||||
ui: ui_version(),
|
|
||||||
debug_mode: __build.development,
|
|
||||||
type: "web"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
load_scripts: async () => {
|
load_scripts: async () => {
|
||||||
if(!window.require) {
|
if(!window.require) {
|
||||||
await loader.scripts.load(["vendor/jquery/jquery.min.js"], { cache_tag: cache_tag() });
|
await loader.scripts.load(["vendor/jquery/jquery.min.js"], { cache_tag: cache_tag() });
|
||||||
|
@ -101,15 +83,19 @@ const loader_javascript = {
|
||||||
loader.critical_error("Failed to load manifest.json", error);
|
loader.critical_error("Failed to load manifest.json", error);
|
||||||
throw "failed to load manifest.json";
|
throw "failed to load manifest.json";
|
||||||
}
|
}
|
||||||
if(manifest.version !== 1)
|
if(manifest.version !== 2)
|
||||||
throw "invalid manifest version";
|
throw "invalid manifest version";
|
||||||
|
|
||||||
const chunk_name = loader.version().type === "web" ? "shared-app" : "client-app";
|
const chunk_name = __build.entry_chunk_name;
|
||||||
if(!Array.isArray(manifest.chunks[chunk_name])) {
|
if(typeof manifest.chunks[chunk_name] !== "object") {
|
||||||
loader.critical_error("Missing entry chunk in manifest.json", "Chunk " + chunk_name + " is missing.");
|
loader.critical_error("Missing entry chunk in manifest.json", "Chunk " + chunk_name + " is missing.");
|
||||||
throw "missing entry chunk";
|
throw "missing entry chunk";
|
||||||
}
|
}
|
||||||
await loader.scripts.load_multiple(manifest.chunks[chunk_name].map(e => "js/" + e.file), {
|
loader.module_mapping().push({
|
||||||
|
application: chunk_name,
|
||||||
|
modules: manifest.chunks[chunk_name].modules
|
||||||
|
});
|
||||||
|
await loader.scripts.load_multiple(manifest.chunks[chunk_name].files.map(e => "js/" + e.file), {
|
||||||
cache_tag: undefined,
|
cache_tag: undefined,
|
||||||
max_parallel_requests: -1
|
max_parallel_requests: -1
|
||||||
});
|
});
|
||||||
|
@ -154,7 +140,7 @@ const loader_style = {
|
||||||
["vendor/highlight/styles/darcula.css", ""], /* empty string means not required */
|
["vendor/highlight/styles/darcula.css", ""], /* empty string means not required */
|
||||||
], options);
|
], options);
|
||||||
|
|
||||||
if(loader.version().debug_mode) {
|
if(__build.mode === "debug") {
|
||||||
await loader_style.load_style_debug();
|
await loader_style.load_style_debug();
|
||||||
} else {
|
} else {
|
||||||
await loader_style.load_style_release();
|
await loader_style.load_style_release();
|
||||||
|
@ -293,12 +279,6 @@ loader.register_task(loader.Stage.INITIALIZING, {
|
||||||
priority: 20
|
priority: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
loader.register_task(loader.Stage.INITIALIZING, {
|
|
||||||
name: "app type test",
|
|
||||||
function: loader_javascript.detect_type,
|
|
||||||
priority: 20
|
|
||||||
});
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.JAVASCRIPT, {
|
loader.register_task(loader.Stage.JAVASCRIPT, {
|
||||||
name: "javascript",
|
name: "javascript",
|
||||||
function: loader_javascript.load_scripts,
|
function: loader_javascript.load_scripts,
|
||||||
|
@ -398,9 +378,14 @@ loader.register_task(loader.Stage.SETUP, {
|
||||||
});
|
});
|
||||||
|
|
||||||
export function run() {
|
export function run() {
|
||||||
window["Module"] = (window["Module"] || {}) as any;
|
window["Module"] = (window["Module"] || {}) as any; /* Why? */
|
||||||
|
|
||||||
/* TeaClient */
|
/* TeaClient */
|
||||||
if(node_require) {
|
if(node_require) {
|
||||||
|
if(__build.target !== "client") {
|
||||||
|
loader.critical_error("App seems not to be compiled for the client.", "This app has been compiled for " + __build.target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
window.native_client = true;
|
window.native_client = true;
|
||||||
|
|
||||||
const path = node_require("path");
|
const path = node_require("path");
|
||||||
|
@ -415,6 +400,11 @@ export function run() {
|
||||||
priority: 40
|
priority: 40
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
if(__build.target !== "web") {
|
||||||
|
loader.critical_error("App seems not to be compiled for the web.", "This app has been compiled for " + __build.target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.native_client = false;
|
window.native_client = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,15 @@ export enum Stage {
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
export function version() : AppVersion;
|
export type ModuleMapping = {
|
||||||
|
application: string,
|
||||||
|
modules: {
|
||||||
|
"id": string,
|
||||||
|
"context": string,
|
||||||
|
"resource": string
|
||||||
|
}[]
|
||||||
|
};
|
||||||
|
export function module_mapping() : ModuleMapping;
|
||||||
|
|
||||||
export function finished();
|
export function finished();
|
||||||
export function running();
|
export function running();
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
const webpack = require("webpack");
|
|
||||||
const path = require('path');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
|
|
||||||
let isDevelopment = process.env.NODE_ENV === 'development';
|
|
||||||
isDevelopment = true;
|
|
||||||
module.exports = {
|
|
||||||
entry: path.join(__dirname, "app/index.ts"),
|
|
||||||
devtool: 'inline-source-map',
|
|
||||||
mode: "development",
|
|
||||||
plugins: [
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: isDevelopment ? '[name].css' : '[name].[hash].css',
|
|
||||||
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__build: {
|
|
||||||
development: isDevelopment,
|
|
||||||
version: '0000' //TODO!
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.s[ac]ss$/,
|
|
||||||
loader: [
|
|
||||||
//isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
|
|
||||||
'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: true,
|
|
||||||
sourceMap: isDevelopment
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: isDevelopment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.tsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
|
|
||||||
loader: [
|
|
||||||
{
|
|
||||||
loader: 'ts-loader',
|
|
||||||
options: {
|
|
||||||
transpileOnly: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.tsx', '.ts', '.js', ".scss"],
|
|
||||||
alias: { }
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
filename: 'loader.js',
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
library: "loader",
|
|
||||||
libraryTarget: "window" //"var" | "assign" | "this" | "window" | "self" | "global" | "commonjs" | "commonjs2" | "commonjs-module" | "amd" | "amd-require" | "umd" | "umd2" | "jsonp" | "system"
|
|
||||||
},
|
|
||||||
optimization: { }
|
|
||||||
};
|
|
|
@ -21,9 +21,7 @@
|
||||||
"build-web": "webpack --config webpack-web.config.js",
|
"build-web": "webpack --config webpack-web.config.js",
|
||||||
"watch-web": "webpack --watch --config webpack-web.config.js",
|
"watch-web": "webpack --watch --config webpack-web.config.js",
|
||||||
"build-client": "webpack --config webpack-client.config.js",
|
"build-client": "webpack --config webpack-client.config.js",
|
||||||
"watch-client": "webpack --watch --config webpack-client.config.js",
|
"watch-client": "webpack --watch --config webpack-client.config.js"
|
||||||
"build-loader": "webpack --config loader/webpack.config.js",
|
|
||||||
"watch-loader": "webpack --watch --config loader/webpack.config.js"
|
|
||||||
},
|
},
|
||||||
"author": "TeaSpeak (WolverinDEV)",
|
"author": "TeaSpeak (WolverinDEV)",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as log from "tc-shared/log";
|
import * as log from "tc-shared/log";
|
||||||
|
import * as hex from "tc-shared/crypto/hex";
|
||||||
import {LogCategory} from "tc-shared/log";
|
import {LogCategory} from "tc-shared/log";
|
||||||
import {ChannelEntry} from "tc-shared/ui/channel";
|
import {ChannelEntry} from "tc-shared/ui/channel";
|
||||||
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
||||||
|
|
|
@ -126,7 +126,7 @@ export namespace bbcode {
|
||||||
},
|
},
|
||||||
name: tr("Open URL in Browser"),
|
name: tr("Open URL in Browser"),
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
visible: loader.version().type === "native" && false // Currently not possible
|
visible: __build.target === "client" && false // Currently not possible
|
||||||
}, contextmenu.Entry.HR(), {
|
}, contextmenu.Entry.HR(), {
|
||||||
callback: () => copy_to_clipboard(url),
|
callback: () => copy_to_clipboard(url),
|
||||||
name: tr("Copy URL to clipboard"),
|
name: tr("Copy URL to clipboard"),
|
||||||
|
|
|
@ -250,7 +250,7 @@ export class Group {
|
||||||
|
|
||||||
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
|
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
|
||||||
name: "log enabled initialisation",
|
name: "log enabled initialisation",
|
||||||
function: async () => initialize(loader.version().debug_mode ? LogType.TRACE : LogType.INFO),
|
function: async () => initialize(__build.mode === "debug" ? LogType.TRACE : LogType.INFO),
|
||||||
priority: 150
|
priority: 150
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ async function initialize_app() {
|
||||||
try { //Initialize main template
|
try { //Initialize main template
|
||||||
const main = $("#tmpl_main").renderTag({
|
const main = $("#tmpl_main").renderTag({
|
||||||
multi_session: !settings.static_global(Settings.KEY_DISABLE_MULTI_SESSION),
|
multi_session: !settings.static_global(Settings.KEY_DISABLE_MULTI_SESSION),
|
||||||
app_version: loader.version().ui
|
app_version: __build.version
|
||||||
}).dividerfy();
|
}).dividerfy();
|
||||||
|
|
||||||
$("body").append(main);
|
$("body").append(main);
|
||||||
|
@ -589,7 +589,7 @@ loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
|
||||||
try {
|
try {
|
||||||
await initialize();
|
await initialize();
|
||||||
|
|
||||||
if(loader.version().type == "web") {
|
if(__build.target == "web") {
|
||||||
loader.register_task(loader.Stage.LOADED, task_certificate_callback);
|
loader.register_task(loader.Stage.LOADED, task_certificate_callback);
|
||||||
} else {
|
} else {
|
||||||
loader.register_task(loader.Stage.LOADED, task_teaweb_starter);
|
loader.register_task(loader.Stage.LOADED, task_teaweb_starter);
|
||||||
|
|
|
@ -515,4 +515,4 @@ export class ServerSettings extends SettingsBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export let settings: Settings;
|
export let settings: Settings = null;
|
|
@ -370,7 +370,7 @@ export function initialize() {
|
||||||
return true;
|
return true;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if(loader.version().type !== "web") {
|
if(__build.target !== "web") {
|
||||||
menu.append_hr();
|
menu.append_hr();
|
||||||
|
|
||||||
item = menu.append_item(tr("Quit"));
|
item = menu.append_item(tr("Quit"));
|
||||||
|
@ -532,7 +532,7 @@ export function initialize() {
|
||||||
{
|
{
|
||||||
const menu = driver_.append_item(tr("Help"));
|
const menu = driver_.append_item(tr("Help"));
|
||||||
|
|
||||||
if(loader.version().type !== "web") {
|
if(__build.target !== "web") {
|
||||||
item = menu.append_item(tr("Check for updates"));
|
item = menu.append_item(tr("Check for updates"));
|
||||||
item.click(() => native_actions.check_native_update());
|
item.click(() => native_actions.check_native_update());
|
||||||
|
|
||||||
|
@ -546,7 +546,7 @@ export function initialize() {
|
||||||
item = menu.append_item(tr("Visit TeaSpeak forum"));
|
item = menu.append_item(tr("Visit TeaSpeak forum"));
|
||||||
item.click(() => window.open('https://forum.teaspeak.de/', '_blank'));
|
item.click(() => window.open('https://forum.teaspeak.de/', '_blank'));
|
||||||
|
|
||||||
if(loader.version().type !== "web" && typeof(native_actions.show_dev_tools) === "function" && native_actions.show_dev_tools()) {
|
if(__build.target !== "web" && typeof(native_actions.show_dev_tools) === "function" && native_actions.show_dev_tools()) {
|
||||||
menu.append_hr();
|
menu.append_hr();
|
||||||
item = menu.append_item(tr("Open developer tools"));
|
item = menu.append_item(tr("Open developer tools"));
|
||||||
item.click(() => native_actions.open_dev_tools());
|
item.click(() => native_actions.open_dev_tools());
|
||||||
|
@ -556,7 +556,7 @@ export function initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.append_hr();
|
menu.append_hr();
|
||||||
item = menu.append_item(loader.version().type === "web" ? tr("About TeaWeb") : tr("About TeaClient"));
|
item = menu.append_item(__build.target === "web" ? tr("About TeaWeb") : tr("About TeaClient"));
|
||||||
item.click(() => spawnAbout())
|
item.click(() => spawnAbout())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,9 @@ export function spawnAbout() {
|
||||||
header: tr("About"),
|
header: tr("About"),
|
||||||
body: () => {
|
body: () => {
|
||||||
let tag = $("#tmpl_about").renderTag({
|
let tag = $("#tmpl_about").renderTag({
|
||||||
client: loader.version().type !== "web",
|
client: __build.target !== "web",
|
||||||
|
|
||||||
version_client: loader.version().type === "web" ? app_version || "in-dev" : "loading...",
|
version_client: __build.target === "web" ? app_version || "in-dev" : "loading...",
|
||||||
version_ui: app_version || "in-dev",
|
version_ui: app_version || "in-dev",
|
||||||
|
|
||||||
version_timestamp: !!app_version ? format_date(Date.now()) : "--"
|
version_timestamp: !!app_version ? format_date(Date.now()) : "--"
|
||||||
|
@ -43,7 +43,7 @@ export function spawnAbout() {
|
||||||
connectModal.htmlTag.find(".modal-body").addClass("modal-about");
|
connectModal.htmlTag.find(".modal-body").addClass("modal-about");
|
||||||
connectModal.open();
|
connectModal.open();
|
||||||
|
|
||||||
if(loader.version().type !== "web") {
|
if(__build.target !== "web") {
|
||||||
(window as any).native.client_version().then(version => {
|
(window as any).native.client_version().then(version => {
|
||||||
connectModal.htmlTag.find(".version-client").text(version);
|
connectModal.htmlTag.find(".version-client").text(version);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function spawnKeySelect(callback: (key?: KeyEvent) => void) {
|
||||||
|
|
||||||
|
|
||||||
button_save.on('click', () => {
|
button_save.on('click', () => {
|
||||||
if(loader.version().type !== "web") {
|
if(__build.version !== "web") {
|
||||||
/* Because pressing the close button is also a mouse action */
|
/* Because pressing the close button is also a mouse action */
|
||||||
if(current_key_age + 1000 > Date.now() && current_key.key_code == "MOUSE2")
|
if(current_key_age + 1000 > Date.now() && current_key.key_code == "MOUSE2")
|
||||||
current_key = last_key;
|
current_key = last_key;
|
||||||
|
|
|
@ -24,9 +24,9 @@ const last_step: {[key: string]:string} = (() => {
|
||||||
|
|
||||||
export function openModalNewcomer() : Modal {
|
export function openModalNewcomer() : Modal {
|
||||||
let modal = createModal({
|
let modal = createModal({
|
||||||
header: tra("Welcome to the {}", loader.version().type === "web" ? "TeaSpeak - Web client" : "TeaSpeak - Client"),
|
header: tra("Welcome to the {}", __build.version === "web" ? "TeaSpeak - Web client" : "TeaSpeak - Client"),
|
||||||
body: () => $("#tmpl_newcomer").renderTag({
|
body: () => $("#tmpl_newcomer").renderTag({
|
||||||
is_web: loader.version().type === "web"
|
is_web: __build.version === "web"
|
||||||
}).children(),
|
}).children(),
|
||||||
footer: null,
|
footer: null,
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ function settings_general_language(container: JQuery, modal: Modal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
container.find(".button-restart").on('click', () => {
|
container.find(".button-restart").on('click', () => {
|
||||||
if(loader.version().type === "web") {
|
if(__build.target === "web") {
|
||||||
location.reload();
|
location.reload();
|
||||||
} else {
|
} else {
|
||||||
createErrorModal(tr("Not implemented"), tr("Client restart isn't implemented.<br>Please do it manually!")).open();
|
createErrorModal(tr("Not implemented"), tr("Client restart isn't implemented.<br>Please do it manually!")).open();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import * as sha1 from "../crypto/sha";
|
||||||
|
|
||||||
export function hashPassword(password: string) : Promise<string> {
|
export function hashPassword(password: string) : Promise<string> {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
sha.sha1(password).then(result => {
|
sha1.sha1(password).then(result => {
|
||||||
resolve(btoa(String.fromCharCode.apply(null, new Uint8Array(result))));
|
resolve(btoa(String.fromCharCode.apply(null, new Uint8Array(result))));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,7 +64,7 @@ function _generate(config: Configuration, node: ts.Node, result: TranslationEntr
|
||||||
|
|
||||||
node.forEachChild(n => _generate(config, n, result));
|
node.forEachChild(n => _generate(config, n, result));
|
||||||
}
|
}
|
||||||
function create_unique_check(source_file: ts.SourceFile, variable: ts.Expression, variables: { name: string, node: ts.Node }[]) : ts.Node[] {
|
function create_unique_check(config: Configuration, source_file: ts.SourceFile, variable: ts.Expression, variables: { name: string, node: ts.Node }[]) : ts.Node[] {
|
||||||
const nodes: ts.Node[] = [], blocked_nodes: ts.Statement[] = [];
|
const nodes: ts.Node[] = [], blocked_nodes: ts.Statement[] = [];
|
||||||
|
|
||||||
const node_path = (node: ts.Node) => {
|
const node_path = (node: ts.Node) => {
|
||||||
|
@ -90,10 +90,10 @@ function create_unique_check(source_file: ts.SourceFile, variable: ts.Expression
|
||||||
|
|
||||||
/* initialization */
|
/* initialization */
|
||||||
{
|
{
|
||||||
const declarations = ts.createElementAccess(variable, ts.createLiteral("declared"));
|
const declarations = ts.createElementAccess(variable, ts.createLiteral(config.variables.declarations));
|
||||||
nodes.push(ts.createAssignment(declarations, ts.createBinary(declarations, SyntaxKind.BarBarToken, ts.createAssignment(declarations, ts.createObjectLiteral()))));
|
nodes.push(ts.createAssignment(declarations, ts.createBinary(declarations, SyntaxKind.BarBarToken, ts.createAssignment(declarations, ts.createObjectLiteral()))));
|
||||||
|
|
||||||
declarations_file = ts.createElementAccess(variable, ts.createLiteral("declared_files"));
|
declarations_file = ts.createElementAccess(variable, ts.createLiteral(config.variables.declare_files));
|
||||||
nodes.push(ts.createAssignment(declarations_file, ts.createBinary(declarations_file, SyntaxKind.BarBarToken, ts.createAssignment(declarations_file, ts.createObjectLiteral()))));
|
nodes.push(ts.createAssignment(declarations_file, ts.createBinary(declarations_file, SyntaxKind.BarBarToken, ts.createAssignment(declarations_file, ts.createObjectLiteral()))));
|
||||||
|
|
||||||
variable = declarations;
|
variable = declarations;
|
||||||
|
@ -126,8 +126,8 @@ function create_unique_check(source_file: ts.SourceFile, variable: ts.Expression
|
||||||
const for_variable_name = ts.createLoopVariable();
|
const for_variable_name = ts.createLoopVariable();
|
||||||
const for_variable_path = ts.createLoopVariable();
|
const for_variable_path = ts.createLoopVariable();
|
||||||
const for_declaration = ts.createVariableDeclarationList([ts.createVariableDeclaration(ts.createObjectBindingPattern([
|
const for_declaration = ts.createVariableDeclarationList([ts.createVariableDeclaration(ts.createObjectBindingPattern([
|
||||||
ts.createBindingElement(undefined, "name", for_variable_name, undefined),
|
ts.createBindingElement(undefined, config.optimized ? "n": "name", for_variable_name, undefined),
|
||||||
ts.createBindingElement(undefined, "path", for_variable_path, undefined)])
|
ts.createBindingElement(undefined, config.optimized ? "p": "path", for_variable_path, undefined)])
|
||||||
, undefined, undefined)]);
|
, undefined, undefined)]);
|
||||||
|
|
||||||
let for_block: ts.Statement;
|
let for_block: ts.Statement;
|
||||||
|
@ -151,8 +151,8 @@ function create_unique_check(source_file: ts.SourceFile, variable: ts.Expression
|
||||||
let block = ts.createForOf(undefined,
|
let block = ts.createForOf(undefined,
|
||||||
for_declaration, ts.createArrayLiteral(
|
for_declaration, ts.createArrayLiteral(
|
||||||
[...variables.map(e => ts.createObjectLiteral([
|
[...variables.map(e => ts.createObjectLiteral([
|
||||||
ts.createPropertyAssignment("name", ts.createLiteral(e.name)),
|
ts.createPropertyAssignment(config.optimized ? "n": "name", ts.createLiteral(e.name)),
|
||||||
ts.createPropertyAssignment("path", ts.createLiteral(node_path(e.node)))
|
ts.createPropertyAssignment(config.optimized ? "p": "path", ts.createLiteral(node_path(e.node)))
|
||||||
]))
|
]))
|
||||||
])
|
])
|
||||||
, for_block);
|
, for_block);
|
||||||
|
@ -166,52 +166,69 @@ export function transform(config: Configuration, context: ts.TransformationConte
|
||||||
const cache: VolatileTransformConfig = {} as any;
|
const cache: VolatileTransformConfig = {} as any;
|
||||||
cache.translations = [];
|
cache.translations = [];
|
||||||
|
|
||||||
|
config.variables = (config.variables || {}) as any;
|
||||||
|
config.variables.base = config.variables.base || (config.optimized ? "__tr" : "_translations");
|
||||||
|
config.variables.declare_files = config.variables.declare_files || (config.optimized ? "f" : "declare_files");
|
||||||
|
config.variables.declarations = config.variables.declarations || (config.optimized ? "d" : "definitions");
|
||||||
|
|
||||||
//Initialize nodes
|
//Initialize nodes
|
||||||
const extra_nodes: ts.Node[] = [];
|
const extra_nodes: ts.Node[] = [];
|
||||||
{
|
{
|
||||||
cache.nodes = {} as any;
|
cache.nodes = {} as any;
|
||||||
if(config.use_window) {
|
if(config.use_window) {
|
||||||
const window = ts.createIdentifier("window");
|
const window = ts.createIdentifier("window");
|
||||||
let translation_map = ts.createPropertyAccess(window, ts.createIdentifier("_translations"));
|
let translation_map = ts.createPropertyAccess(window, ts.createIdentifier(config.variables.base));
|
||||||
const new_translations = ts.createAssignment(translation_map, ts.createObjectLiteral());
|
const new_translations = ts.createAssignment(translation_map, ts.createObjectLiteral());
|
||||||
|
|
||||||
let translation_map_init: ts.Expression = ts.createBinary(translation_map, ts.SyntaxKind.BarBarToken, new_translations);
|
let translation_map_init: ts.Expression = ts.createBinary(translation_map, ts.SyntaxKind.BarBarToken, new_translations);
|
||||||
translation_map_init = ts.createParen(translation_map_init);
|
translation_map_init = ts.createParen(translation_map_init);
|
||||||
|
|
||||||
|
extra_nodes.push(translation_map_init);
|
||||||
cache.nodes = {
|
cache.nodes = {
|
||||||
translation_map: translation_map,
|
translation_map: translation_map
|
||||||
translation_map_init: translation_map_init
|
};
|
||||||
|
} else if(config.module) {
|
||||||
|
cache.nodes = {
|
||||||
|
translation_map: ts.createIdentifier(config.variables.base)
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
const variable_name = "_translations";
|
|
||||||
const variable_map = ts.createIdentifier(variable_name);
|
|
||||||
|
|
||||||
|
extra_nodes.push(ts.createVariableDeclarationList([
|
||||||
|
ts.createVariableDeclaration(config.variables.base, undefined, ts.createObjectLiteral())
|
||||||
|
], ts.NodeFlags.Const), ts.createToken(SyntaxKind.SemicolonToken));
|
||||||
|
} else {
|
||||||
|
const variable_map = ts.createIdentifier(config.variables.base);
|
||||||
const inline_if = ts.createBinary(ts.createBinary(ts.createTypeOf(variable_map), SyntaxKind.ExclamationEqualsEqualsToken, ts.createLiteral("undefined")), ts.SyntaxKind.BarBarToken, ts.createAssignment(variable_map, ts.createObjectLiteral()));
|
const inline_if = ts.createBinary(ts.createBinary(ts.createTypeOf(variable_map), SyntaxKind.ExclamationEqualsEqualsToken, ts.createLiteral("undefined")), ts.SyntaxKind.BarBarToken, ts.createAssignment(variable_map, ts.createObjectLiteral()));
|
||||||
|
|
||||||
cache.nodes = {
|
cache.nodes = {
|
||||||
translation_map: variable_map,
|
translation_map: variable_map,
|
||||||
translation_map_init: variable_map
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//ts.createVariableDeclarationList([ts.createVariableDeclaration(variable_name)], ts.NodeFlags.Let)
|
|
||||||
extra_nodes.push(inline_if);
|
extra_nodes.push(inline_if);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const used_names = [config.variables.declarations, config.variables.declare_files];
|
||||||
const generated_names: { name: string, node: ts.Node }[] = [];
|
const generated_names: { name: string, node: ts.Node }[] = [];
|
||||||
|
let generator_base = 0;
|
||||||
cache.name_generator = (config, node, message) => {
|
cache.name_generator = (config, node, message) => {
|
||||||
const characters = "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
const characters = "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
let name = "";
|
let name;
|
||||||
while(name.length < 8) {
|
do {
|
||||||
const char = characters[Math.floor(Math.random() * characters.length)];
|
name = "";
|
||||||
name = name + char;
|
|
||||||
if(name[0] >= '0' && name[0] <= '9')
|
if(config.module) {
|
||||||
name = name.substr(1) || "";
|
name = "_" + generator_base++;
|
||||||
}
|
} else {
|
||||||
|
/* Global namespace. We've to generate a random name so no duplicates happen */
|
||||||
|
while(name.length < 8) {
|
||||||
|
const char = characters[Math.floor(Math.random() * characters.length)];
|
||||||
|
name = name + char;
|
||||||
|
if(name[0] >= '0' && name[0] <= '9')
|
||||||
|
name = name.substr(1) || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(used_names.findIndex(e => e === name) !== -1);
|
||||||
|
|
||||||
//FIXME
|
|
||||||
//if(generated_names.indexOf(name) != -1)
|
|
||||||
// return cache.name_generator(config, node, message);
|
|
||||||
generated_names.push({name: name, node: node});
|
generated_names.push({name: name, node: node});
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
@ -221,7 +238,10 @@ export function transform(config: Configuration, context: ts.TransformationConte
|
||||||
return replace_processor(config, cache, node, source_file);
|
return replace_processor(config, cache, node, source_file);
|
||||||
}
|
}
|
||||||
source_file = ts.visitNode(source_file, visit);
|
source_file = ts.visitNode(source_file, visit);
|
||||||
extra_nodes.push(...create_unique_check(source_file, cache.nodes.translation_map_init, generated_names));
|
if(!config.module) {
|
||||||
|
/* we don't need a unique check because we're just in our scope */
|
||||||
|
extra_nodes.push(...create_unique_check(config, source_file, cache.nodes.translation_map, generated_names));
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
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);
|
||||||
|
|
||||||
|
@ -262,7 +282,7 @@ export function replace_processor(config: Configuration, cache: VolatileTransfor
|
||||||
console.log("Message: %o", object.text || object.getText(source_file));
|
console.log("Message: %o", object.text || object.getText(source_file));
|
||||||
|
|
||||||
const variable_name = ts.createIdentifier(cache.name_generator(config, node, object.text || object.getText(source_file)));
|
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_init = ts.createPropertyAccess(cache.nodes.translation_map, variable_name);
|
||||||
|
|
||||||
const variable = ts.createPropertyAccess(cache.nodes.translation_map, variable_name);
|
const variable = ts.createPropertyAccess(cache.nodes.translation_map, variable_name);
|
||||||
const new_variable = ts.createAssignment(variable, call);
|
const new_variable = ts.createAssignment(variable, call);
|
||||||
|
@ -284,6 +304,15 @@ export interface Configuration {
|
||||||
use_window?: boolean;
|
use_window?: boolean;
|
||||||
replace_cache?: boolean;
|
replace_cache?: boolean;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
|
||||||
|
optimized?: boolean;
|
||||||
|
module?: boolean;
|
||||||
|
|
||||||
|
variables?: {
|
||||||
|
base: string,
|
||||||
|
declarations: string,
|
||||||
|
declare_files: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransformResult {
|
export interface TransformResult {
|
||||||
|
@ -294,7 +323,6 @@ export interface TransformResult {
|
||||||
interface VolatileTransformConfig {
|
interface VolatileTransformConfig {
|
||||||
nodes: {
|
nodes: {
|
||||||
translation_map: ts.Expression;
|
translation_map: ts.Expression;
|
||||||
translation_map_init: ts.Expression;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
name_generator: (config: Configuration, node: ts.Node, message: string) => string;
|
name_generator: (config: Configuration, node: ts.Node, message: string) => string;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {TranslationEntry} from "./generator";
|
||||||
export interface Config {
|
export interface Config {
|
||||||
target_file?: string;
|
target_file?: string;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
optimized?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let process_config: Config;
|
let process_config: Config;
|
||||||
|
@ -37,6 +38,7 @@ export default function(program: ts.Program, config?: Config) : (context: ts.Tra
|
||||||
return ctx => transformer(ctx) as any;
|
return ctx => transformer(ctx) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processed = [];
|
||||||
const translations: TranslationEntry[] = [];
|
const translations: TranslationEntry[] = [];
|
||||||
const transformer = (context: ts.TransformationContext) =>
|
const transformer = (context: ts.TransformationContext) =>
|
||||||
(rootNode: ts.Node) => {
|
(rootNode: ts.Node) => {
|
||||||
|
@ -51,10 +53,17 @@ const transformer = (context: ts.TransformationContext) =>
|
||||||
} else if(rootNode.kind == ts.SyntaxKind.SourceFile) {
|
} else if(rootNode.kind == ts.SyntaxKind.SourceFile) {
|
||||||
const file = rootNode as ts.SourceFile;
|
const file = rootNode as ts.SourceFile;
|
||||||
|
|
||||||
|
if(processed.findIndex(e => e === file.fileName) !== -1) {
|
||||||
|
console.log("Skipping %s (already processed)", file.fileName);
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
|
processed.push(file.fileName);
|
||||||
console.log("Processing " + file.fileName);
|
console.log("Processing " + file.fileName);
|
||||||
const result = ts_generator.transform({
|
const result = ts_generator.transform({
|
||||||
use_window: false,
|
use_window: false,
|
||||||
replace_cache: true
|
replace_cache: true,
|
||||||
|
module: true,
|
||||||
|
optimized: process_config.optimized
|
||||||
}, context, file);
|
}, context, file);
|
||||||
translations.push(...result.translations);
|
translations.push(...result.translations);
|
||||||
return result.node;
|
return result.node;
|
||||||
|
|
|
@ -1,28 +1,21 @@
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
const config = require("./webpack.config");
|
import * as config_base from "./webpack.config";
|
||||||
|
|
||||||
let isDevelopment = process.env.NODE_ENV === 'development';
|
const config = config_base.config();
|
||||||
isDevelopment = true;
|
Object.assign(config.entry, {
|
||||||
|
|
||||||
config.entry = {
|
|
||||||
"client-app": "./client/js/index.ts"
|
"client-app": "./client/js/index.ts"
|
||||||
};
|
});
|
||||||
|
|
||||||
config.resolve.alias = {
|
Object.assign(config.resolve.alias, {
|
||||||
"tc-shared": path.resolve(__dirname, "shared/js"),
|
"tc-shared": path.resolve(__dirname, "shared/js"),
|
||||||
/* backend hasn't declared but its available via "require()" */
|
/* backend hasn't declared but its available via "require()" */
|
||||||
"tc-backend": path.resolve(__dirname, "shared/backend.d"),
|
"tc-backend": path.resolve(__dirname, "shared/backend.d"),
|
||||||
};
|
});
|
||||||
|
|
||||||
config.externals = [
|
config.externals.push((context, request: string, callback) => {
|
||||||
{
|
if (request.startsWith("tc-backend/"))
|
||||||
"tc-loader": "window loader"
|
return callback(null, `window["backend-loader"].require("${request}")`);
|
||||||
},
|
callback();
|
||||||
(context, request: string, callback) => {
|
});
|
||||||
if (request.startsWith("tc-backend/"))
|
|
||||||
return callback(null, `window["backend-loader"].require("${request}")`);
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export = config;
|
export = config;
|
|
@ -1,115 +1,16 @@
|
||||||
import * as ts from "typescript";
|
import * as path from "path";
|
||||||
import trtransformer, {Config} from "./tools/trgen/ts_transformer";
|
import * as config_base from "./webpack.config";
|
||||||
|
|
||||||
const path = require('path');
|
const config = config_base.config();
|
||||||
const webpack = require("webpack");
|
Object.assign(config.entry, {
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
"shared-app": "./web/js/index.ts"
|
||||||
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');
|
|
||||||
|
|
||||||
let isDevelopment = process.env.NODE_ENV === 'development';
|
Object.assign(config.resolve.alias, {
|
||||||
isDevelopment = true;
|
"tc-shared": path.resolve(__dirname, "shared/js"),
|
||||||
module.exports = {
|
"tc-backend/web": path.resolve(__dirname, "web/js"),
|
||||||
entry: {
|
"tc-backend": path.resolve(__dirname, "web/js"),
|
||||||
"shared-app": "./web/js/index.ts"
|
"tc-generated/codec/opus": path.resolve(__dirname, "asm/generated/TeaWeb-Worker-Codec-Opus.js"),
|
||||||
},
|
});
|
||||||
devtool: isDevelopment ? "inline-source-map" : undefined,
|
|
||||||
mode: isDevelopment ? "development" : "production",
|
|
||||||
plugins: [
|
|
||||||
new CleanWebpackPlugin(),
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: isDevelopment ? '[name].css' : '[name].[hash].css',
|
|
||||||
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
|
|
||||||
}),
|
|
||||||
new ManifestGenerator({
|
|
||||||
file: path.join(__dirname, "dist/manifest.json")
|
|
||||||
}),
|
|
||||||
new WorkerPlugin(),
|
|
||||||
//new BundleAnalyzerPlugin()
|
|
||||||
/*
|
|
||||||
new CircularDependencyPlugin({
|
|
||||||
//exclude: /a\.js|node_modules/,
|
|
||||||
failOnError: true,
|
|
||||||
allowAsyncCycles: false,
|
|
||||||
cwd: process.cwd(),
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
new webpack.optimize.AggressiveSplittingPlugin({
|
|
||||||
minSize: 1024 * 8,
|
|
||||||
maxSize: 1024 * 128
|
|
||||||
})
|
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.s[ac]ss$/,
|
|
||||||
loader: [
|
|
||||||
isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: true,
|
|
||||||
sourceMap: isDevelopment
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: isDevelopment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.tsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
|
|
||||||
loader: [
|
export = config;
|
||||||
{
|
|
||||||
loader: 'ts-loader',
|
|
||||||
options: {
|
|
||||||
transpileOnly: true,
|
|
||||||
getCustomTransformers: (prog: ts.Program) => {
|
|
||||||
return {
|
|
||||||
before: [trtransformer(prog, {})]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.was?t$/,
|
|
||||||
loader: [
|
|
||||||
"./webpack/WatLoader.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.tsx', '.ts', '.js', ".scss"],
|
|
||||||
alias: {
|
|
||||||
"tc-shared": path.resolve(__dirname, "shared/js"),
|
|
||||||
"tc-backend/web": path.resolve(__dirname, "web/js"),
|
|
||||||
"tc-backend": path.resolve(__dirname, "web/js"),
|
|
||||||
"tc-generated/codec/opus": path.resolve(__dirname, "asm/generated/TeaWeb-Worker-Codec-Opus.js"),
|
|
||||||
//"tc-backend": path.resolve(__dirname, "shared/backend.d"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
"tc-loader": "window loader"
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
filename: '[contenthash].js',
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
publicPath: "js/"
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
splitChunks: { },
|
|
||||||
minimize: !isDevelopment,
|
|
||||||
minimizer: [new TerserPlugin()]
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as ts from "typescript";
|
import * as ts from "typescript";
|
||||||
import trtransformer, {Config} from "./tools/trgen/ts_transformer";
|
import * as fs from "fs";
|
||||||
|
import trtransformer from "./tools/trgen/ts_transformer";
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
|
@ -10,10 +11,32 @@ const WorkerPlugin = require('worker-plugin');
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
|
||||||
let isDevelopment = process.env.NODE_ENV === 'development';
|
export let isDevelopment = process.env.NODE_ENV === 'development';
|
||||||
isDevelopment = true;
|
isDevelopment = true;
|
||||||
export = {
|
|
||||||
entry: {}, /* will be individually set */
|
const generate_definitions = () => {
|
||||||
|
const git_rev = fs.readFileSync(path.join(__dirname, ".git", "HEAD")).toString();
|
||||||
|
let version;
|
||||||
|
if(git_rev.indexOf("/") === -1)
|
||||||
|
version = git_rev;
|
||||||
|
else
|
||||||
|
version = fs.readFileSync(path.join(__dirname, ".git", git_rev.substr(5).trim())).toString().substr(0, 7);
|
||||||
|
|
||||||
|
return {
|
||||||
|
"__build": {
|
||||||
|
target: JSON.stringify("web"),
|
||||||
|
mode: JSON.stringify(isDevelopment ? "debug" : "release"),
|
||||||
|
version: JSON.stringify(version),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
entry_chunk_name: JSON.stringify("shared-app")
|
||||||
|
} as BuildDefinitions
|
||||||
|
} as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config = () => { return {
|
||||||
|
entry: {
|
||||||
|
"loader": "./loader/app/index.ts"
|
||||||
|
},
|
||||||
|
|
||||||
devtool: isDevelopment ? "inline-source-map" : undefined,
|
devtool: isDevelopment ? "inline-source-map" : undefined,
|
||||||
mode: isDevelopment ? "development" : "production",
|
mode: isDevelopment ? "development" : "production",
|
||||||
|
@ -24,7 +47,8 @@ export = {
|
||||||
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
|
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
|
||||||
}),
|
}),
|
||||||
new ManifestGenerator({
|
new ManifestGenerator({
|
||||||
file: path.join(__dirname, "dist/manifest.json")
|
file: path.join(__dirname, "dist/manifest.json"),
|
||||||
|
base: __dirname
|
||||||
}),
|
}),
|
||||||
new WorkerPlugin(),
|
new WorkerPlugin(),
|
||||||
//new BundleAnalyzerPlugin()
|
//new BundleAnalyzerPlugin()
|
||||||
|
@ -39,7 +63,8 @@ export = {
|
||||||
isDevelopment ? undefined : new webpack.optimize.AggressiveSplittingPlugin({
|
isDevelopment ? undefined : new webpack.optimize.AggressiveSplittingPlugin({
|
||||||
minSize: 1024 * 8,
|
minSize: 1024 * 8,
|
||||||
maxSize: 1024 * 128
|
maxSize: 1024 * 128
|
||||||
})
|
}),
|
||||||
|
new webpack.DefinePlugin(generate_definitions())
|
||||||
].filter(e => !!e),
|
].filter(e => !!e),
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
@ -73,7 +98,9 @@ export = {
|
||||||
transpileOnly: true,
|
transpileOnly: true,
|
||||||
getCustomTransformers: (prog: ts.Program) => {
|
getCustomTransformers: (prog: ts.Program) => {
|
||||||
return {
|
return {
|
||||||
before: [trtransformer(prog, {})]
|
before: [trtransformer(prog, {
|
||||||
|
optimized: true
|
||||||
|
})]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,19 +117,21 @@ export = {
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.tsx', '.ts', '.js', ".scss"],
|
extensions: ['.tsx', '.ts', '.js', ".scss"],
|
||||||
alias: { }, /* will be individually set */
|
alias: { },
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
"tc-loader": "window loader"
|
|
||||||
},
|
},
|
||||||
|
externals: [
|
||||||
|
{"tc-loader": "window loader"}
|
||||||
|
] as any[],
|
||||||
output: {
|
output: {
|
||||||
filename: isDevelopment ? '[name].js' : '[contenthash].js',
|
filename: isDevelopment ? '[name].js' : '[contenthash].js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
publicPath: "js/"
|
publicPath: "js/"
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
splitChunks: { },
|
splitChunks: {
|
||||||
|
|
||||||
|
},
|
||||||
minimize: !isDevelopment,
|
minimize: !isDevelopment,
|
||||||
minimizer: [new TerserPlugin()]
|
minimizer: [new TerserPlugin()]
|
||||||
}
|
}
|
||||||
};
|
}};
|
|
@ -1,8 +1,10 @@
|
||||||
import * as webpack from "webpack";
|
import * as webpack from "webpack";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
file?: string;
|
file?: string;
|
||||||
|
base: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ManifestGenerator {
|
class ManifestGenerator {
|
||||||
|
@ -10,32 +12,51 @@ class ManifestGenerator {
|
||||||
|
|
||||||
readonly options: Options;
|
readonly options: Options;
|
||||||
constructor(options: Options) {
|
constructor(options: Options) {
|
||||||
this.options = options || {};
|
this.options = options || { base: __dirname };
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(compiler: webpack.Compiler) {
|
apply(compiler: webpack.Compiler) {
|
||||||
compiler.hooks.afterCompile.tap(this.constructor.name, compilation => {
|
compiler.hooks.afterCompile.tap(this.constructor.name, compilation => {
|
||||||
const chunks_data = {};
|
const chunks_data = {};
|
||||||
for(const chunk_group of compilation.chunkGroups) {
|
for(const chunk_group of compilation.chunkGroups) {
|
||||||
console.log(chunk_group.options.name);
|
|
||||||
const js_files = [];
|
const js_files = [];
|
||||||
|
const modules = [];
|
||||||
|
|
||||||
for(const chunk of chunk_group.chunks) {
|
for(const chunk of chunk_group.chunks) {
|
||||||
if(chunk.files.length !== 1) throw "expected only one file per chunk";
|
if(chunk.files.length !== 1) throw "expected only one file per chunk";
|
||||||
|
|
||||||
const file = chunk.files[0];
|
|
||||||
console.log("Chunk: %s - %s - %s", chunk.id, chunk.hash, file);
|
|
||||||
//console.log(chunk);
|
|
||||||
//console.log(" - %s - %o", chunk.id, chunk);
|
|
||||||
js_files.push({
|
js_files.push({
|
||||||
hash: chunk.hash,
|
hash: chunk.hash,
|
||||||
file: file
|
file: chunk.files[0]
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
|
for(const module of chunk._modules) {
|
||||||
|
if(!module.type.startsWith("javascript/"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!module.resource || !module.context)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(module.context !== path.dirname(module.resource))
|
||||||
|
throw "invalid context/resource relation";
|
||||||
|
|
||||||
|
modules.push({
|
||||||
|
id: module.id,
|
||||||
|
context: path.relative(this.options.base, module.context).replace(/\\/g, "/"),
|
||||||
|
resource: path.basename(module.resource)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
chunks_data[chunk_group.options.name] = js_files;
|
|
||||||
|
chunks_data[chunk_group.options.name] = {
|
||||||
|
files: js_files,
|
||||||
|
modules: modules
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.manifest_content = {
|
this.manifest_content = {
|
||||||
version: 1,
|
version: 2,
|
||||||
chunks: chunks_data
|
chunks: chunks_data
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
declare global {
|
||||||
|
interface BuildDefinitions {
|
||||||
|
target: "web" | "client";
|
||||||
|
mode: "release" | "debug";
|
||||||
|
|
||||||
|
/* chunk for the loader to load initially */
|
||||||
|
entry_chunk_name: string;
|
||||||
|
|
||||||
|
version: string;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const __build: BuildDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
Loading…
Reference in New Issue