164 lines
4.6 KiB
TypeScript
164 lines
4.6 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 }[];
|
|
}
|
|
|
|
/**
|
|
* Simple find and replace in assets plugin for Webpack
|
|
*/
|
|
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);
|
|
|
|
if (matches) {
|
|
logger.info(`${from} | Found ${matches.length} 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|mjs)$/,
|
|
// https://webpack.js.org/loaders/babel-loader/#exclude-libraries-that-should-not-be-transpiled
|
|
exclude: [
|
|
// \\ for Windows, / for macOS and Linux
|
|
/node_modules[\\/]core-js/,
|
|
],
|
|
use: {
|
|
loader: "babel-loader",
|
|
options: {
|
|
targets: "defaults",
|
|
sourceType: "unambiguous",
|
|
presets: [
|
|
// Parse TypeScript
|
|
["@babel/preset-typescript"],
|
|
[
|
|
"@babel/preset-env",
|
|
{
|
|
// Use this to cover the lowest possible syntax requirement for QtScript
|
|
// See: https://browsersl.ist/
|
|
targets: "cover 100%",
|
|
// Adds at the top of each file imports of polyfills only for features used in the current and not supported by target environments
|
|
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", ".mjs"],
|
|
// Explicitly define where node_modules is in this project for corejs imports
|
|
// See: https://stackoverflow.com/a/62129649
|
|
modules: [path.resolve(__dirname, "node_modules")],
|
|
},
|
|
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":' },
|
|
/**
|
|
* Some Regexp uses "/" character in character sets but must be escaped in QtScript syntax (don't know why)
|
|
*/
|
|
{ from: /\[\^\\s\(\/\]/g, to: "[^\\s(\\/]" },
|
|
{ from: /\[\\w\.\/\]/g, to: "[\\w.\\/]" },
|
|
{ from: /\[a-z_\+-\/\]/g, to: "[a-z_+-\\/]" },
|
|
],
|
|
}),
|
|
],
|
|
optimization: {
|
|
minimize: false,
|
|
},
|
|
};
|
|
|
|
export default config;
|