146 lines
3.8 KiB
TypeScript
146 lines
3.8 KiB
TypeScript
import path from "path";
|
|
import { readdirSync } from "fs";
|
|
import { Compilation, sources } from "webpack";
|
|
import type {
|
|
Configuration,
|
|
RuleSetRule,
|
|
Compiler,
|
|
EntryObject,
|
|
} from "webpack";
|
|
|
|
interface FindReplacePluginOptions {
|
|
replace: { from: RegExp; to: string }[];
|
|
}
|
|
|
|
class FindReplacePlugin {
|
|
options: FindReplacePluginOptions;
|
|
|
|
constructor(options: FindReplacePluginOptions) {
|
|
this.options = options;
|
|
}
|
|
|
|
apply(compiler: Compiler) {
|
|
const pluginName = FindReplacePlugin.name;
|
|
const logger = compiler.getInfrastructureLogger(pluginName);
|
|
|
|
compiler.hooks.compilation.tap({ name: pluginName }, (compilation) => {
|
|
compilation.hooks.processAssets.tap(
|
|
{
|
|
name: pluginName,
|
|
stage: Compilation.PROCESS_ASSETS_STAGE_ANALYSE,
|
|
},
|
|
(assets) => {
|
|
Object.entries(assets).forEach(([pathname, source]) => {
|
|
if (path.extname(pathname) !== ".js") return;
|
|
|
|
let replaced = source.source().toString();
|
|
|
|
// For every regex pattern, replace it in the source content
|
|
for (const { from, to } of this.options.replace) {
|
|
const matches = replaced.match(from);
|
|
logger.info(
|
|
from,
|
|
to,
|
|
`Found ${matches ? matches.length : 0} matches`,
|
|
matches,
|
|
);
|
|
|
|
replaced = replaced.replace(from, to);
|
|
}
|
|
|
|
const newSource = new sources.RawSource(replaced);
|
|
|
|
const previousSize = source.size();
|
|
compilation.updateAsset(pathname, newSource);
|
|
const newSize = newSource.size();
|
|
|
|
if (newSize !== previousSize) {
|
|
logger.info(
|
|
`Found and replaced in ${pathname}: ${previousSize} -> ${newSize}`,
|
|
);
|
|
}
|
|
});
|
|
},
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
const babelRule: RuleSetRule = {
|
|
test: /\.(ts|js)$/,
|
|
use: {
|
|
loader: "babel-loader",
|
|
options: {
|
|
targets: "defaults",
|
|
sourceType: "unambiguous",
|
|
presets: [
|
|
["@babel/preset-typescript"],
|
|
[
|
|
"@babel/preset-env",
|
|
{
|
|
// Use this to cover the lowest possible syntax requirement for QtScript
|
|
// See: https://browsersl.ist/
|
|
targets: "cover 100%",
|
|
useBuiltIns: "usage",
|
|
corejs: "3.46.0",
|
|
},
|
|
],
|
|
],
|
|
},
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Dynamically returns an object of script entries from src/scripts/*.ts files
|
|
*/
|
|
function getScriptsEntryObject(): EntryObject {
|
|
const entries: EntryObject = {};
|
|
const scriptsPath = path.resolve(__dirname, "src", "scripts");
|
|
const scripts = readdirSync(scriptsPath).filter((file) =>
|
|
file.endsWith(".ts"),
|
|
);
|
|
|
|
scripts.forEach((script) => {
|
|
entries[path.parse(script).name] = path.resolve(scriptsPath, script);
|
|
});
|
|
|
|
return entries;
|
|
}
|
|
|
|
const config: Configuration = {
|
|
mode: "production",
|
|
module: {
|
|
rules: [babelRule],
|
|
},
|
|
entry: getScriptsEntryObject(),
|
|
resolve: { extensions: [".ts", ".js"] },
|
|
output: {
|
|
filename: "[name].js",
|
|
path: path.resolve(__dirname, "dist"),
|
|
environment: { arrowFunction: false },
|
|
},
|
|
plugins: [
|
|
new FindReplacePlugin({
|
|
replace: [
|
|
/**
|
|
* Replaces reserved words as property names
|
|
* For example obj.for = 0 -> obj["for"] = 0
|
|
*/
|
|
{ from: /\.(for|return)([^\w])/g, to: '["$1"]$2' },
|
|
/**
|
|
* Replaces reserved words as object literal property names
|
|
* See: https://eslint.style/rules/quote-props#quote-props
|
|
* For example { for: 0 } -> { "for": 0 }
|
|
*/
|
|
{ from: /(for|return):/g, to: '"$1":' },
|
|
{ from: /\/(.*)\[([^\]]*)\/([^\]]*)\](.*)\//g, to: "/$1[$2\/$3]$4/" },
|
|
],
|
|
}),
|
|
],
|
|
optimization: {
|
|
minimize: false,
|
|
},
|
|
};
|
|
|
|
export default config;
|