Including the assemble files into webpack

This commit is contained in:
WolverinDEV 2020-08-05 18:25:08 +02:00
parent d6f7f85b8b
commit 2a2cfee8b0
10 changed files with 184 additions and 170 deletions

81
file.ts
View file

@ -85,42 +85,23 @@ const APP_FILE_LIST_SHARED_SOURCE: ProjectResource[] = [
"path": "img/", "path": "img/",
"local-path": "./shared/img/" "local-path": "./shared/img/"
}
];
const APP_FILE_LIST_SHARED_VENDORS: ProjectResource[] = [];
const APP_FILE_LIST_CLIENT_SOURCE: ProjectResource[] = [
{ /* client css files */
"client-only": true,
"type": "css",
"search-pattern": /.*\.css$/,
"build-target": "dev|rel",
"path": "css/",
"local-path": "./client/css/"
}, },
{ /* client js files */ { /* assembly files */
"client-only": true,
"type": "js",
"search-pattern": /.*\.js/,
"build-target": "dev",
"path": "js/",
"local-path": "./client/js/"
}
];
const APP_FILE_LIST_WEB_SOURCE: ProjectResource[] = [
{ /* generated assembly files */
"web-only": true, "web-only": true,
"type": "wasm", "type": "wasm",
"search-pattern": /.*\.(wasm)/, "search-pattern": /.*\.(wasm)/,
"build-target": "dev|rel", "build-target": "dev|rel",
"path": "wasm/", "path": "js/",
"local-path": "./web/native-codec/generated/" "local-path": "./dist/"
}, }
];
const APP_FILE_LIST_SHARED_VENDORS: ProjectResource[] = [];
const APP_FILE_LIST_CLIENT_SOURCE: ProjectResource[] = [];
const APP_FILE_LIST_WEB_SOURCE: ProjectResource[] = [
{ /* translations */ { /* translations */
"web-only": true, /* Only required for the web client */ "web-only": true, /* Only required for the web client */
"type": "i18n", "type": "i18n",
@ -289,8 +270,6 @@ namespace server {
search_options: SearchOptions; search_options: SearchOptions;
} }
const exec: (command: string) => Promise<{ stdout: string, stderr: string }> = util.promisify(cp.exec);
let files: ProjectResource[] = []; let files: ProjectResource[] = [];
let server: http.Server; let server: http.Server;
let options: Options; let options: Options;
@ -333,7 +312,7 @@ namespace server {
} }
} }
async function serve_file(pathname: string, query: any, response: http.ServerResponse) { async function serve_file(pathname: string, response: http.ServerResponse) {
const file = await generator.search_http_file(files, pathname, options.search_options); const file = await generator.search_http_file(files, pathname, options.search_options);
if(!file) { if(!file) {
console.log("[SERVER] Client requested unknown file %s", pathname); console.log("[SERVER] Client requested unknown file %s", pathname);
@ -358,7 +337,7 @@ namespace server {
fis.on("data", data => response.write(data)); fis.on("data", data => response.write(data));
} }
async function handle_api_request(request: http.IncomingMessage, response: http.ServerResponse, url: url_utils.UrlWithParsedQuery) { async function handle_api_request(response: http.ServerResponse, url: url_utils.UrlWithParsedQuery) {
if(url.query["type"] === "files") { if(url.query["type"] === "files") {
response.writeHead(200, { "info-version": 1 }); response.writeHead(200, { "info-version": 1 });
response.write("type\thash\tpath\tname\n"); response.write("type\thash\tpath\tname\n");
@ -369,7 +348,7 @@ namespace server {
} else if(url.query["type"] === "file") { } else if(url.query["type"] === "file") {
let p = path.join(url.query["path"] as string, url.query["name"] as string).replace(/\\/g, "/"); let p = path.join(url.query["path"] as string, url.query["name"] as string).replace(/\\/g, "/");
if(!p.startsWith("/")) p = "/" + p; if(!p.startsWith("/")) p = "/" + p;
serve_file(p, url.query, response); await serve_file(p, response);
return; return;
} }
@ -395,12 +374,12 @@ namespace server {
if(url.pathname === "/api.php") { if(url.pathname === "/api.php") {
//Client API //Client API
handle_api_request(request, response, url); handle_api_request(response, url);
return; return;
} else if(url.pathname === "/") { } else if(url.pathname === "/") {
url.pathname = "/index.html"; url.pathname = "/index.html";
} }
serve_file(url.pathname, url.query, response); serve_file(url.pathname, response);
} }
} }
@ -526,28 +505,6 @@ namespace watcher {
} }
} }
export class TSCWatcher extends Watcher {
constructor() {
super("TSC");
//this.verbose = true;
}
protected start_command(): string[] {
return ["npm", "run", "tsc", "--", "-w"];
}
}
export class SASSWatcher extends Watcher {
constructor() {
super("SASS");
this.verbose = false;
}
protected start_command(): string[] {
return ["npm", "run", "sass", "--", "--watch", "shared/css:shared/css"];
}
}
export class WebPackWatcher extends Watcher { export class WebPackWatcher extends Watcher {
private readonly target; private readonly target;
@ -576,7 +533,7 @@ async function main_serve(target: "client" | "web", mode: "rel" | "dev", port: n
console.log("Server started on %d", port); console.log("Server started on %d", port);
console.log("To stop the server press ^K^C."); console.log("To stop the server press ^K^C.");
await new Promise(resolve => {}); await new Promise(() => {});
} }
async function main_develop(node: boolean, target: "client" | "web", port: number, flags: string[]) { async function main_develop(node: boolean, target: "client" | "web", port: number, flags: string[]) {
@ -626,7 +583,7 @@ async function main_develop(node: boolean, target: "client" | "web", port: numbe
async function git_tag() { async function git_tag() {
const git_rev = fs.readFileSync(path.join(__dirname, ".git", "HEAD")).toString(); const git_rev = fs.readFileSync(path.join(__dirname, ".git", "HEAD")).toString();
let version;
if(git_rev.indexOf("/") === -1) if(git_rev.indexOf("/") === -1)
return git_rev.substr(0, 7); return git_rev.substr(0, 7);
else else
@ -655,7 +612,7 @@ async function main_generate(target: "client" | "web", mode: "rel" | "dev", dest
const exec = util.promisify(cp.exec); const exec = util.promisify(cp.exec);
linker = async (source, target) => { linker = async (source, target) => {
const command = "ln -s " + source + " " + target; const command = "ln -s " + source + " " + target;
const { stdout, stderr } = await exec(command); const { stderr } = await exec(command);
if(stderr) if(stderr)
throw "failed to create link: " + stderr; throw "failed to create link: " + stderr;
} }

35
package-lock.json generated
View file

@ -1,5 +1,5 @@
{ {
"name": "client", "name": "teaspeak-web",
"version": "1.2.0", "version": "1.2.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
@ -1373,6 +1373,7 @@
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/jsrender/-/jsrender-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/jsrender/-/jsrender-1.0.5.tgz",
"integrity": "sha512-Fjdp5QACaBMsd5vpx9x27rggFa0nyd8zqWnuTw8Aum4+gM/NiQubb6pweE3sgfHwrjRh7BGjYydpE4WYbsB+Ow==", "integrity": "sha512-Fjdp5QACaBMsd5vpx9x27rggFa0nyd8zqWnuTw8Aum4+gM/NiQubb6pweE3sgfHwrjRh7BGjYydpE4WYbsB+Ow==",
"dev": true,
"requires": { "requires": {
"jsrender": "*" "jsrender": "*"
} }
@ -4765,6 +4766,38 @@
"integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==",
"dev": true "dev": true
}, },
"file-loader": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz",
"integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^2.6.5"
},
"dependencies": {
"json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
}
}
},
"file-uri-to-path": { "file-uri-to-path": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",

View file

@ -17,7 +17,6 @@
"author": "TeaSpeak (WolverinDEV)", "author": "TeaSpeak (WolverinDEV)",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/jsrender": "^1.0.5",
"@babel/core": "^7.10.4", "@babel/core": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.10.4", "@babel/plugin-transform-runtime": "^7.10.4",
"@babel/preset-env": "^7.10.4", "@babel/preset-env": "^7.10.4",
@ -29,6 +28,7 @@
"@types/fs-extra": "^8.0.1", "@types/fs-extra": "^8.0.1",
"@types/html-minifier": "^3.5.3", "@types/html-minifier": "^3.5.3",
"@types/jquery": "^3.3.34", "@types/jquery": "^3.3.34",
"@types/jsrender": "^1.0.5",
"@types/loader-utils": "^1.1.3", "@types/loader-utils": "^1.1.3",
"@types/lodash": "^4.14.149", "@types/lodash": "^4.14.149",
"@types/moment": "^2.13.0", "@types/moment": "^2.13.0",
@ -48,6 +48,7 @@
"csso-cli": "^3.0.0", "csso-cli": "^3.0.0",
"ejs": "^3.0.2", "ejs": "^3.0.2",
"exports-loader": "^0.7.0", "exports-loader": "^0.7.0",
"file-loader": "^6.0.0",
"fs-extra": "latest", "fs-extra": "latest",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"html-loader": "^1.0.0", "html-loader": "^1.0.0",

View file

@ -17,6 +17,7 @@
"webpack/EJSGenerator.ts", "webpack/EJSGenerator.ts",
"webpack/WatLoader.ts", "webpack/WatLoader.ts",
"webpack/DevelBlocks.ts", "webpack/DevelBlocks.ts",
"webpack/EmscriptenLoader.ts",
"loader/IndexGenerator.ts", "loader/IndexGenerator.ts",

View file

@ -12,6 +12,7 @@
"paths": { "paths": {
"*": ["shared/declarations/*"], "*": ["shared/declarations/*"],
"tc-shared/*": ["shared/js/*"], "tc-shared/*": ["shared/js/*"],
"tc-backend/web/assembly/*": ["web/native-codec/generated/*"], /* specific web part */
"tc-backend/web/*": ["web/app/*"], /* specific web part */ "tc-backend/web/*": ["web/app/*"], /* specific web part */
"tc-backend/*": ["shared/backend.d/*"], "tc-backend/*": ["shared/backend.d/*"],
"tc-loader": ["loader/exports/loader.d.ts"], "tc-loader": ["loader/exports/loader.d.ts"],

View file

@ -2,32 +2,27 @@ import * as cworker from "./CodecWorker";
import {CodecType} from "tc-backend/web/codec/Codec"; import {CodecType} from "tc-backend/web/codec/Codec";
import {CodecWorker} from "./CodecWorker"; import {CodecWorker} from "./CodecWorker";
declare global {
interface Window {
__init_em_module: ((Module: any) => void)[];
}
}
self.__init_em_module = self.__init_em_module || [];
const WASM_ERROR_MESSAGES = [ const WASM_ERROR_MESSAGES = [
'no native wasm support detected' 'no native wasm support detected'
]; ];
let Module; interface OpusModuleType extends EmscriptenModule {
self.__init_em_module.push(m => Module = m); cwrap: typeof cwrap;
const runtime_initialize_promise = new Promise((resolve, reject) => { }
self.__init_em_module.push(Module => {
let OpusModule = {} as OpusModuleType;
const runtimeInitializedPromise = new Promise((resolve, reject) => {
const cleanup = () => { const cleanup = () => {
Module['onRuntimeInitialized'] = undefined; OpusModule['onRuntimeInitialized'] = undefined;
Module['onAbort'] = undefined; OpusModule['onAbort'] = undefined;
}; };
Module['onRuntimeInitialized'] = () => { OpusModule['onRuntimeInitialized'] = () => {
cleanup(); cleanup();
resolve(); resolve();
}; };
Module['onAbort'] = error => { OpusModule['onAbort'] = error => {
cleanup(); cleanup();
let message; let message;
@ -42,10 +37,8 @@ const runtime_initialize_promise = new Promise((resolve, reject) => {
reject(message); reject(message);
} }
}); });
});
self.__init_em_module.push(Module => { OpusModule['print'] = function() {
Module['print'] = function() {
const message = arguments[0] as string; const message = arguments[0] as string;
if(message.startsWith("CompileError: WebAssembly.instantiate(): ")) { if(message.startsWith("CompileError: WebAssembly.instantiate(): ")) {
/* Compile errors also get printed to error stream so no need to log them here */ /* Compile errors also get printed to error stream so no need to log them here */
@ -54,7 +47,7 @@ self.__init_em_module.push(Module => {
console.log(...arguments); console.log(...arguments);
}; };
Module['printErr'] = function() { OpusModule['printErr'] = function() {
const message = arguments[0] as string; const message = arguments[0] as string;
if(message.startsWith("wasm streaming compile failed: ")) { if(message.startsWith("wasm streaming compile failed: ")) {
const error_message = message.substr(31); const error_message = message.substr(31);
@ -89,19 +82,26 @@ self.__init_em_module.push(Module => {
console.error(...arguments); console.error(...arguments);
}; };
Module['locateFile'] = file => "../../wasm/" + file;
});
self.addEventListener("unhandledrejection", event => { self.addEventListener("unhandledrejection", event => {
let message;
if(event.reason instanceof Error) { if(event.reason instanceof Error) {
if(event.reason.name === "RuntimeError" && event.reason.message.startsWith("abort(CompileError: WebAssembly.instantiate():")) { if(event.reason.name !== "RuntimeError")
return;
else
message = event.reason.message;
} else if(typeof event.reason === "string") {
message = event.reason;
} else {
return;
}
if(message.startsWith("abort(CompileError: WebAssembly.instantiate():")) {
/* /*
We already handled that error via the Module['printErr'] callback. We already handled that error via the Module['printErr'] callback.
*/ */
event.preventDefault(); event.preventDefault();
return; return;
} }
}
}); });
enum OpusType { enum OpusType {
@ -145,15 +145,15 @@ class OpusWorker implements CodecWorker {
} }
initialise?() : string { initialise?() : string {
this.fn_newHandle = Module.cwrap("codec_opus_createNativeHandle", "number", ["number", "number"]); this.fn_newHandle = OpusModule.cwrap("codec_opus_createNativeHandle", "number", ["number", "number"]);
this.fn_decode = Module.cwrap("codec_opus_decode", "number", ["number", "number", "number", "number"]); this.fn_decode = OpusModule.cwrap("codec_opus_decode", "number", ["number", "number", "number", "number"]);
this.fn_encode = Module.cwrap("codec_opus_encode", "number", ["number", "number", "number", "number"]); this.fn_encode = OpusModule.cwrap("codec_opus_encode", "number", ["number", "number", "number", "number"]);
this.fn_reset = Module.cwrap("codec_opus_reset", "number", ["number"]); this.fn_reset = OpusModule.cwrap("codec_opus_reset", "number", ["number"]);
this.nativeHandle = this.fn_newHandle(this.channelCount, this.type); this.nativeHandle = this.fn_newHandle(this.channelCount, this.type);
this.nativeBufferPtr = Module._malloc(OpusWorker.kProcessBufferSize); this.nativeBufferPtr = OpusModule._malloc(OpusWorker.kProcessBufferSize);
this.processBuffer = new Uint8Array(Module.HEAPU8.buffer, this.nativeBufferPtr, OpusWorker.kProcessBufferSize); this.processBuffer = new Uint8Array(OpusModule.HEAPU8.buffer, this.nativeBufferPtr, OpusWorker.kProcessBufferSize);
return undefined; return undefined;
} }
@ -197,19 +197,26 @@ cworker.register_codec(CodecType.OPUS_VOICE, async () => new OpusWorker(1, OpusT
cworker.set_initialize_callback(async () => { cworker.set_initialize_callback(async () => {
try { try {
require("tc-generated/codec/opus"); /* could be directly required since it's just a file reference */
} catch (e) { const [ moduleCreator, wasmFile ] = await Promise.all([
if(Module) { import("tc-backend/web/assembly/TeaWeb-Worker-Codec-Opus.js"),
if(typeof(Module['onAbort']) === "function") {
Module['onAbort']("Failed to load native scripts");
} /* else the error had been already handled because its a WASM error */
} else {
throw e;
}
}
if(!Module)
throw "Missing module handle";
await runtime_initialize_promise; // @ts-ignore
import("tc-backend/web/assembly/TeaWeb-Worker-Codec-Opus.wasm")
]);
const module = moduleCreator(Object.assign(OpusModule, {
locateFile(file: string) {
return file.endsWith(".wasm") ? wasmFile.default : file;
}
}));
if(module !== OpusModule)
throw "invalid opus module object";
} catch (e) {
OpusModule['onAbort']("Failed to load native scripts");
}
await runtimeInitializedPromise;
return true; return true;
}); });

View file

@ -18,7 +18,7 @@ endfunction()
import_opus() import_opus()
set(CMAKE_CXX_FLAGS "-O3 --llvm-lto 1 --memory-init-file 0 -s WASM=1 -s ASSERTIONS=1") # -s ALLOW_MEMORY_GROWTH=1 -O3 set(CMAKE_CXX_FLAGS "-O3 --llvm-lto 1 --memory-init-file 0 -s WASM=1 -s ASSERTIONS=1") # -s ALLOW_MEMORY_GROWTH=1 -O3
set(CMAKE_EXE_LINKER_FLAGS "-s EXPORTED_FUNCTIONS='[\"_malloc\", \"_free\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -s ENVIRONMENT='worker' --pre-js ${CMAKE_SOURCE_DIR}/init.js") # set(CMAKE_EXE_LINKER_FLAGS "-s MODULARIZE=1 -s EXPORTED_FUNCTIONS='[\"_malloc\", \"_free\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -s ENVIRONMENT='worker' --pre-js ${CMAKE_SOURCE_DIR}/init.js") #
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/generated/") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/generated/")
add_executable(TeaWeb-Worker-Codec-Opus src/opus.cpp) add_executable(TeaWeb-Worker-Codec-Opus src/opus.cpp)

View file

@ -10,6 +10,7 @@ cd build_ || exit 1
emcmake cmake .. || { emcmake cmake .. || {
echo "emcmake cmake failed for the first time, trying it again" #IDKW but sometimes it does not work the first try echo "emcmake cmake failed for the first time, trying it again" #IDKW but sometimes it does not work the first try
cd . # Sometimes helps
emcmake cmake .. || { emcmake cmake .. || {
echo "Failed to execute cmake" echo "Failed to execute cmake"
exit 1 exit 1

View file

@ -8,10 +8,13 @@ export = () => config_base.config("web").then(config => {
Object.assign(config.resolve.alias, { Object.assign(config.resolve.alias, {
"tc-shared": path.resolve(__dirname, "shared/js"), "tc-shared": path.resolve(__dirname, "shared/js"),
"tc-backend/web/assembly": path.resolve(__dirname, "web/native-codec/generated"),
"tc-backend/web": path.resolve(__dirname, "web/app"), "tc-backend/web": path.resolve(__dirname, "web/app"),
"tc-backend": path.resolve(__dirname, "web/app"), "tc-backend": path.resolve(__dirname, "web/app"),
"tc-generated/codec/opus": path.resolve(__dirname, "web/native-codec/generated/TeaWeb-Worker-Codec-Opus.js"),
}); });
config.node = config.node || {};
config.node["fs"] = "empty";
return Promise.resolve(config); return Promise.resolve(config);
}); });

View file

@ -88,6 +88,7 @@ export const config = async (target: "web" | "client"): Promise<Configuration> =
isDevelopment: isDevelopment isDevelopment: isDevelopment
}) })
].filter(e => !!e), ].filter(e => !!e),
module: { module: {
rules: [ rules: [
{ {
@ -175,6 +176,15 @@ export const config = async (target: "web" | "client"): Promise<Configuration> =
"./webpack/WatLoader.js" "./webpack/WatLoader.js"
] ]
}, },
{
test: /\.wasm$/,
type: 'javascript/auto',
loader: 'file-loader',
options: {
/* the public path will already be set by emscripten base path */
publicPath: './'
}
},
{ {
test: /\.svg$/, test: /\.svg$/,
loader: 'svg-inline-loader' loader: 'svg-inline-loader'