WebPack Update

This commit is contained in:
Josef 2025-03-31 14:00:55 +02:00
parent 1238a1ff7c
commit f8edbdd581
9 changed files with 858 additions and 6 deletions

View File

@ -119,7 +119,7 @@ export class PageHandler
private _maxPreloadingDurationMS:number = 2000; private _maxPreloadingDurationMS:number = 2000;
private static _localHost = "http://localhost:8080"; private static _localHost = "http://localhost:8080";
private static _localNetworkRegexPattern = /^(http:\/\/\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d?:XXXX)/ private static _localNetworkRegexPattern = /^(http:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}?:XXXX)/
private static _localNetworkRegex = RegExpUtility.createRegExp( this._localNetworkRegexPattern, "XXXX", 8080 + "" ); private static _localNetworkRegex = RegExpUtility.createRegExp( this._localNetworkRegexPattern, "XXXX", 8080 + "" );
private _isHTMLMode:boolean = false; private _isHTMLMode:boolean = false;
private _fileLocation:string = ""; private _fileLocation:string = "";
@ -187,16 +187,24 @@ export class PageHandler
{ {
let adress = this.trimmedLocation; let adress = this.trimmedLocation;
// console.log( "Checking adress for localhost", adress, PageHandler._localHost, PageHandler._localNetworkRegex );
if ( adress.startsWith( PageHandler._localHost ) ) if ( adress.startsWith( PageHandler._localHost ) )
{ {
console.log( "Is starting with localhost" );
return true; return true;
} }
// console.log( "Not starting with localhost" );
if ( PageHandler._localNetworkRegex.test( adress ) ) if ( PageHandler._localNetworkRegex.test( adress ) )
{ {
// console.log( "Is starting with localhost regex" );
return true; return true;
} }
// console.log( "Not starting with localhost regex" );
return false; return false;
} }
@ -234,7 +242,7 @@ export class PageHandler
} }
else else
{ {
console.log( "LOADING PAGE DATA FROM JSON" ); console.log( "LOADING PAGE DATA FROM JSON", this.isLocalNetwork, pagesPath );
let pagesData = await Loader.loadJSON<PagesJSON>( pagesPath ); let pagesData = await Loader.loadJSON<PagesJSON>( pagesPath );
pages = pagesData.pages; pages = pagesData.pages;
} }

86
node/DOMShim.ts Normal file
View File

@ -0,0 +1,86 @@
import { JSDOM } from "jsdom";
export class DOMShim
{
private static _instance:DOMShim = null;
static get $():DOMShim
{
if ( this._instance )
{
return this._instance
}
this._instance = new DOMShim();
return this._instance;
}
private _applied = false;
private _jsDOM:JSDOM;
constructor()
{
this._apply();
}
setDocument( html:string )
{
this._jsDOM = new JSDOM( html );
( global as any ).window = this._jsDOM.window;
( global as any ).document = this._jsDOM.window.document;
}
get jsdom(){ return this._jsDOM; }
private _apply()
{
if ( this._applied )
{
return;
}
this._addHTMLNodeDefinition();
this._addDOMParser();
this._applied = true;
}
private _addHTMLNodeDefinition()
{
( global as any ).Node =
{
ELEMENT_NODE: 1,
ATTRIBUTE_NODE: 2,
TEXT_NODE:3,
CDATA_SECTION_NODE:4,
PROCESSING_INSTRUCTION_NODE:7,
COMMENT_NODE:8,
DOCUMENT_NODE:9,
DOCUMENT_TYPE_NODE:10,
DOCUMENT_FRAGMENT_NODE:11
}
}
private _addDOMParser()
{
DOMParserShim.implementation = ( html:string, type:string = "html" )=>
{
return new JSDOM( html, {contentType:type} ).window.document;
}
global.DOMParser = DOMParserShim;
}
}
export class DOMParserShim
{
static implementation:( html:string, type:string )=>Document;
parseFromString( html:string, type:string ):Document
{
return DOMParserShim.implementation( html, type );
}
}

373
node/files/Files.ts Normal file
View File

@ -0,0 +1,373 @@
import { promises as fs } from "fs";
import * as path from "path";
import { RJLog } from "../log/RJLog";
import { PathReference } from "./PathReference";
import { DOMShim } from "../DOMShim";
import { DateMath } from "../../browser/date/DateMath";
export class Files
{
static parentPath( filePath:string )
{
return path.dirname( filePath );
}
static async forAllIn( filePath:string, filter:(p:PathReference)=>Promise<boolean> = null, action:(p:PathReference)=>Promise<void> = null ):Promise<PathReference[]>
{
let files = await fs.readdir( filePath );
let root = new PathReference( filePath );
let pathReferences = files.map( f => root.createRelative( f ) );
if ( filter )
{
let filteredPaths = [];
for ( let p of pathReferences )
{
if ( await filter( p ) )
{
filteredPaths.push( p );
}
}
pathReferences = filteredPaths;
};
for ( let p of pathReferences )
{
let isDirectory = await p.isDirectory();
if ( isDirectory )
{
await this.forAllIn( p.absolutePath, filter, action );
}
}
if ( action )
{
for ( let p of pathReferences )
{
await action( p );
}
}
return Promise.resolve( pathReferences );
}
static async forDirectChildrenIn( filePath:string, filter:(p:PathReference)=>Promise<boolean> = null, action:(p:PathReference)=>Promise<void> = null ):Promise<PathReference[]>
{
let files = await fs.readdir( filePath );
let root = new PathReference( filePath );
let pathReferences = files.map( f => root.createRelative( f ) );
if ( filter )
{
let filteredPaths = [];
for ( let p of pathReferences )
{
if ( await filter( p ) )
{
filteredPaths.push( p );
}
}
pathReferences = filteredPaths;
};
if ( action )
{
for ( let p of pathReferences )
{
await action( p );
}
}
return Promise.resolve( pathReferences );
}
static joinPaths( pathFragments:string[] )
{
return path.join.apply( path, pathFragments );
}
static async existsIn( directoryPath:string, fileName:string ):Promise<boolean>
{
let combinedPath = Files.joinPaths( [ directoryPath, fileName ] );
let result = await Files.exists( combinedPath );
return Promise.resolve( result );
}
static async getStatistics( filePath:string )
{
return fs.stat( filePath );
}
static async getModificationDate( filePath:string ):Promise<Date>
{
let stats = await this.getStatistics( filePath );
if ( ! stats )
{
return Promise.resolve( null );
}
return new Date( stats.mtimeMs );
}
static async isNewerThan( filePath:string, date:Date ):Promise<boolean>
{
let mDate = await this.getModificationDate( filePath );
return Promise.resolve( DateMath.isAfter( mDate, date ) );
}
static async isDirectory( filePath:string ):Promise<boolean>
{
try
{
let stats = await fs.stat( filePath );
return Promise.resolve( stats !== null && stats !== undefined && stats.isDirectory() );
}
catch( e )
{
return false;
}
return Promise.resolve( false );
}
static async isFile( filePath:string ):Promise<boolean>
{
try
{
let stats = await fs.stat( filePath );
return Promise.resolve( stats !== null && stats !== undefined && stats.isFile() );
}
catch( e )
{
return false;
}
return Promise.resolve( false );
}
static async isSymbolicLink( filePath:string ):Promise<boolean>
{
try
{
let stats = await fs.stat( filePath );
return Promise.resolve( stats !== null && stats !== undefined && stats.isSymbolicLink() );
}
catch( e )
{
return false;
}
return Promise.resolve( false );
}
static async exists( filePath:string ):Promise<boolean>
{
try
{
let stats = await fs.stat( filePath );
return Promise.resolve( stats !== null && stats !== undefined );
}
catch( e )
{
return false;
}
return Promise.resolve( false );
}
static async ensureDirectoryExists( path:string ):Promise<void>
{
let exists = await Files.exists( path );
if ( exists )
{
return Promise.resolve();
}
await fs.mkdir( path, { recursive: true } );
return Promise.resolve();
}
static async ensureParentDirectoryExists( filePath:string ):Promise<void>
{
let path = Files.parentPath( filePath );
let exists = await Files.exists( path );
if ( exists )
{
return Promise.resolve();
}
await fs.mkdir( path );
return Promise.resolve();
}
static async deleteFile( filePath:string ):Promise<boolean>
{
try
{
await fs.unlink( filePath );
}
catch( e )
{
return Promise.resolve( false );
}
return Promise.resolve( true );
}
static async loadUTF8( filePath:string ):Promise<string>
{
try
{
let data = await fs.readFile( filePath );
let stringData = data.toString();
return Promise.resolve( stringData );
}
catch ( exception )
{
RJLog.log( exception );
}
return Promise.resolve( null );
}
static async moveFile( oldPath:string, newPath:string )
{
try
{
await fs.rename( oldPath, newPath );
}
catch ( e )
{
await fs.copyFile( oldPath, newPath );
await fs.unlink( oldPath );
}
}
static async loadJSON<T>( filePath:string ):Promise<T>
{
let text = await Files.loadUTF8( filePath );
if ( text === null )
{
return Promise.resolve( null );
}
try
{
let jsonObject = JSON.parse( text );
return Promise.resolve( jsonObject as T );
}
catch ( exception )
{
RJLog.log( exception );
}
return Promise.resolve( null );
}
static async saveUTF8( filePath:string, text:string ):Promise<boolean>
{
try
{
await fs.writeFile( filePath, text );
return Promise.resolve( true );
}
catch ( exception )
{
RJLog.log( exception );
}
return Promise.resolve( false );
}
static async saveJSON<T>( filePath:string, data:T ):Promise<boolean>
{
try
{
let jsonData = JSON.stringify( data );
let result = await Files.saveUTF8( filePath, jsonData );
return Promise.resolve( result );
}
catch( e )
{
RJLog.log( e );
}
return Promise.resolve( false );
}
static async saveXML( filePath:string, rootElement:Element ):Promise<void>
{
let domShim = DOMShim.$;
let nodeName = rootElement.nodeName;
let xmlHeader = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + "\n";
let serializedXML = `${xmlHeader}<${nodeName}>${rootElement.innerHTML}</${nodeName}>` ;
//RJLog.log( rootElement, serializedXML );
await Files.saveUTF8( filePath, serializedXML );
return Promise.resolve();
}
static async loadXML( filePath:string ):Promise<Document>
{
let domShim = DOMShim.$;
let stringData = await Files.loadUTF8( filePath );
let parser = new DOMParser();
let xmlDoc = parser.parseFromString( stringData, "text/xml" );
return xmlDoc;
}
static async loadHTML( filePath:string ):Promise<Document>
{
let domShim = DOMShim.$;
let stringData = await Files.loadUTF8( filePath );
let parser = new DOMParser();
let xmlDoc = parser.parseFromString( stringData, "text/html" );
return xmlDoc;
}
static async saveHTML( filePath:string, rootElement:Element ):Promise<void>
{
let domShim = DOMShim.$;
await Files.saveUTF8( filePath, rootElement.outerHTML );
return Promise.resolve();
}
}

4
node/files/FilesSync.ts Normal file
View File

@ -0,0 +1,4 @@
export class FilesSync
{
}

26
node/files/PathFilter.ts Normal file
View File

@ -0,0 +1,26 @@
import { PathReference } from "./PathReference"
export type PathReferenceFilter = (p:PathReference)=>Promise<boolean>;
export class PathFilter
{
static get HTML()
{
return PathFilter.forFileExtension( ".html" );
}
static get JSON()
{
return PathFilter.forFileExtension( ".json" );
}
static forFileExtension( extension:string ):PathReferenceFilter
{
let filter = ( p:PathReference )=>
{
return p.isFileWithExtension( extension );
}
return filter;
}
}

151
node/files/PathReference.ts Normal file
View File

@ -0,0 +1,151 @@
import { RegExpUtility } from "../../browser/text/RegExpUtitlity";
import { Files } from "./Files";
export class PathReference
{
_parentReference:PathReference;
_relative:boolean;
_path:string;
_cachedAbsolutePath:string;
constructor( absolutePath:string )
{
this._path = RegExpUtility.normalizePath( absolutePath );
this._relative = false;
this._parentReference = null;
}
createRelative( path:string )
{
path = RegExpUtility.normalizePath( path );
let link = new PathReference( path );
link._relative = true;
link._parentReference = this;
return link;
}
createRelativeFromAbsolute( otherAbsolutePath:string, isFile:boolean )
{
otherAbsolutePath = RegExpUtility.normalizePath( otherAbsolutePath );
if ( ! isFile )
{
let relativePath = RegExpUtility.createRelativeDirectoryPath( this.absolutePath, otherAbsolutePath );
return this.createRelative( relativePath )
}
let filePath = RegExpUtility.fileNameOrLastPath( otherAbsolutePath );
let parentPath = RegExpUtility.parentPath( otherAbsolutePath );
let relativePath = RegExpUtility.createRelativeDirectoryPath( this.absolutePath, parentPath );
relativePath = RegExpUtility.join( relativePath, filePath );
return this.createRelative( relativePath )
}
get isRelative()
{
return this._relative;
}
get relativePath()
{
return this._path;
}
get fileName()
{
return RegExpUtility.fileNameOrLastPath( this._path );
}
get fileNameWithoutExtension()
{
return RegExpUtility.trimFileTypeExtension( this.fileName );
}
pathEndsWith( extension:string )
{
return this._path.toLowerCase().endsWith( extension.toLowerCase() );
}
async isFileWithExtension( extension:string )
{
if ( ! this.pathEndsWith( extension ) )
{
return false;
}
return this.isFile();
}
get absolutePath()
{
if ( ! this._relative )
{
return this._path;
}
if ( this._cachedAbsolutePath )
{
return this._cachedAbsolutePath;
}
let cachedAbsolutePath = RegExpUtility.join( this._parentReference.absolutePath, this._path );
cachedAbsolutePath = RegExpUtility.resolvePath( cachedAbsolutePath );
this._cachedAbsolutePath = cachedAbsolutePath;
return this._cachedAbsolutePath;
}
async exists():Promise<boolean>
{
return Files.exists( this.absolutePath );
}
async isFile():Promise<boolean>
{
return Files.isFile( this.absolutePath );
}
async isDirectory():Promise<boolean>
{
return Files.isDirectory( this.absolutePath );
}
async isSymbolicLink():Promise<boolean>
{
return Files.isSymbolicLink( this.absolutePath );
}
async loadUTF8()
{
return Files.loadUTF8( this.absolutePath );
}
async loadHTML()
{
return Files.loadHTML( this.absolutePath );
}
async saveHTML( rootElement:Element )
{
return Files.saveHTML( this.absolutePath, rootElement );
}
async loadXML()
{
return Files.loadXML( this.absolutePath );
}
async loadJSON<T>()
{
return Files.loadJSON<T>( this.absolutePath );
}
}

View File

@ -1,8 +1,8 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ESNext",
"module": "CommonJS", "module": "es2022",
"lib": ["ESNext"], "target": "es2015",
"moduleResolution": "Node", "moduleResolution": "Node",
"types": ["node"] "types": ["node"]
} }

View File

@ -2,23 +2,100 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { RJLog } from "../log/RJLog"; import { RJLog } from "../log/RJLog";
import { spawn } from "child_process";
export class PagesInfo export class PagesInfo
{ {
pages:string[] = []; pages:string[] = [];
} }
export class PHPServerSettings
{
phpPaths:string[] = [ "D:\\apps\\php\\php.exe", "C:\\apps\\php\\php.exe" ];
relativeWebPath:string;
routerPath:string;
port:number = 8081;
}
export class PHPPagesBuilder export class PHPPagesBuilder
{ {
inputDir:string; inputDir:string;
outputDir:string; outputDir:string;
constructor( source:string, build:string ) static hasServer = false;
constructor( source:string, build:string, settings:PHPServerSettings )
{ {
this.inputDir = source; this.inputDir = source;
this.outputDir = build; this.outputDir = build;
this.startServer( settings );
} }
startServer( settings:PHPServerSettings )
{
if ( settings == null )
{
return;
}
if ( PHPPagesBuilder.hasServer )
{
return;
}
PHPPagesBuilder.hasServer = true;
let phpPath = PHPPagesBuilder.getPHPPath( settings );
if ( ! phpPath )
{
RJLog.error( "PHP was not found!");
RJLog.error( "Ensure PHP is installed and the paths in the settings are configured correctly.");
RJLog.log( "PHP paths from settings of '" + process.argv[ 2 ] + "': ");
RJLog.log( '"' + settings.phpPaths.join( ", " ) + '"' );
return;
}
let workdingDir = process.cwd();
let webPath = path.join( workdingDir, settings.relativeWebPath );
let routerPath = path.join( webPath, "_router_.php" );
let port = settings.port;
let spawnedProcess = spawn( phpPath,["-S", "0.0.0.0:" + port, routerPath, "-t", webPath ] );
spawnedProcess.stdout.on( "data", data => { console.log( data + "" ); } );
spawnedProcess.stderr.on( "data", data => { console.log( data + "" ); } );
spawnedProcess.on( 'error', (error) => {
console.log(`error: ${error.message}`);
});
spawnedProcess.on( "close", code => {
console.log(`child process exited with code ${code}`);
});
}
static getPHPPath( settings:PHPServerSettings )
{
for ( let path of settings.phpPaths )
{
let exists = fs.existsSync( path );
if ( exists )
{
RJLog.log( "Starting php server from:", path );
return path;
}
}
return null;
}
filterFiles( fileName:string ) filterFiles( fileName:string )
{ {
if ( fileName.startsWith( "__" ) ) if ( fileName.startsWith( "__" ) )

View File

@ -0,0 +1,127 @@
import * as fs from "fs";
import * as path from "path";
import { RJLog } from "../log/RJLog";
import { Files } from "../files/Files";
import { PathReference } from "../files/PathReference";
export class TemplatesInfo
{
templates:string[] = [];
}
export class TemplatesIndexBuilder
{
inputDir:string;
outputDir:string;
constructor( source:string, build:string )
{
this.inputDir = source;
this.outputDir = build;
}
filterFiles( fileName:string )
{
if ( fileName.startsWith( "__" ) )
{
return false;
}
return fileName.endsWith( ".html" );
}
apply( compiler:any )
{
compiler.hooks.afterCompile.tapAsync( "TemplatesIndexBuilder",
async ( compilation:any, callback:any ) =>
{
await Files.forAllIn( this.inputDir, null,
async ( p:PathReference ) =>
{
if ( await p.isDirectory() )
{
return Promise.resolve();
}
let fileName = p.fileName;
if ( ! this.filterFiles( fileName ) )
{
return Promise.resolve();
}
compilation.fileDependencies.add( p.absolutePath );
return Promise.resolve();
}
);
callback();
}
);
compiler.hooks.emit.tapAsync( "TemplatesIndexBuilder",
async ( compilation:any, callback:any ) =>
{
let templates = new TemplatesInfo();
let templatesPathReference = new PathReference( path.resolve( this.inputDir ) );
// RJLog.log( templatesPathReference.absolutePath );
await Files.forAllIn( templatesPathReference.absolutePath, null,
async ( p:PathReference ) =>
{
if ( await p.isDirectory() )
{
return Promise.resolve();
}
let fileName = p.fileName;
if ( ! this.filterFiles( fileName ) )
{
return Promise.resolve();
}
let absoluteFilePath = p.absolutePath;
let inputRelativePath = templatesPathReference.createRelativeFromAbsolute( absoluteFilePath, true );
// RJLog.log( "Abs to Rel", absoluteFilePath, inputRelativePath.relativePath );
let outputFileName = path.join( this.outputDir, inputRelativePath.relativePath );
templates.templates.push( inputRelativePath.relativePath );
let content = fs.readFileSync( p.absolutePath, "utf-8" );
// RJLog.log( "Adding", p.absolutePath, outputFileName );
compilation.assets[ outputFileName ] =
{
source: () => content,
size: () => content.length,
};
return Promise.resolve();
}
);
let templatesPath = path.join( this.outputDir, "index.json" );
let templatesJSON = JSON.stringify( templates, null, " " );
compilation.assets[ templatesPath ] =
{
source: () => templatesJSON,
size: () => templatesJSON.length,
};
callback();
return Promise.resolve();
}
);
}
}