Skip to content

Commit

Permalink
Switch to esbuild for generating corelib/wwwroot/index.global.js inst…
Browse files Browse the repository at this point in the history
…ead of rollup. Rollup is only used for dts generation now.
  • Loading branch information
volkanceylan committed Sep 17, 2024
1 parent 8abb3d5 commit 1808751
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 223 deletions.
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
"name": "@serenity-is/workspace-serenity",
"devDependencies": {
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-typescript": "11.1.6",
"@rollup/pluginutils": "5.1.0",
"@swc/core": "1.7.23",
"@swc/jest": "0.2.36",
"@types/jest": "29.5.12",
Expand All @@ -14,8 +12,6 @@
"jsx-dom": "8.1.5",
"rollup": "4.21.2",
"rollup-plugin-dts": "6.1.1",
"terser": "5.31.6",
"tslib": "2.7.0",
"typescript": "5.5.4"
},
"optionalDependencies": {
Expand Down
88 changes: 80 additions & 8 deletions packages/corelib/build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,98 @@ import { fileURLToPath } from 'url';

const root = resolve(join(fileURLToPath(new URL('.', import.meta.url)), '../'));

var coreLibBase = {
const coreLibBase = {
absWorkingDir: resolve(root),
bundle: true,
color: true,
chunkNames: 'chunks/[name]-[hash]',
format: 'esm',
entryPoints: [
'src/index.ts'
],
logLevel: 'info',
outdir: 'dist',
minify: false,
outbase: 'src',
sourcemap: true,
splitting: false,
target: 'es2015'
}

// https://github.com/evanw/esbuild/issues/337
export function importAsGlobalsPlugin(mapping) {
const escRe = (s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
const filter = new RegExp(Object.keys(mapping).map((mod) =>
`^${escRe(mod)}$`).join("|"));

return {
name: "global-imports",
setup(build) {
build.onResolve({ filter }, (args) => {
if (!mapping[args.path])
throw new Error("Unknown global: " + args.path);
return { path: mapping[args.path], namespace: "external-global" };
});

build.onLoad({ filter: /.*/, namespace: "external-global" },
async (args) => {
return { contents: `module.exports = ${args.path};`, loader: "js" };
});
}
};
}

await esbuild.build({
...coreLibBase,
entryPoints: [
'src/index.ts'
],
outbase: 'src',
external: ['@serenity-is/sleekgrid'],
minify: false,
format: 'esm',
outdir: 'dist',
sourcemap: false
});

const corelibGlobalBase = {
...coreLibBase,
banner: {
js: 'var Slick = Slick || {};'
},
footer: {
js: `(function (me) {
if (!me.Q)
me.Q = me.Serenity;
else if (me.Q !== me.Serenity) {
Object.keys(me.Q).forEach(function(key) {
if (me.Q[key] != null &&
me.Serenity[key] == null) {
me.Serenity[key] = me.Q[key];
}
});
me.Q = me.Serenity;
}
me.Slick = me.Slick || {};
['Aggregators', 'AggregateFormatting'].forEach(function(x) {
me.Slick[x] = me.Slick[x] || {};
Object.assign(me.Slick[x], Serenity[x]);
});
['RemoteView'].forEach(function(x) {
me.Slick[x] = Serenity[x];
});
})(this);`
},
format: 'iife',
globalName: 'Serenity',
outfile: 'wwwroot/index.global.js',
plugins: [importAsGlobalsPlugin({
"@serenity-is/sleekgrid": "Slick"
})]
};

await esbuild.build({
...corelibGlobalBase,
minify: false,
outfile: 'wwwroot/index.global.js'
});

await esbuild.build({
...corelibGlobalBase,
lineLimit: 1000,
minify: true,
outfile: 'wwwroot/index.global.min.js'
});
6 changes: 3 additions & 3 deletions packages/corelib/dist/index.d.ts

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions packages/corelib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@
"license": "MIT",
"repository": "https://github.com/serenity-is/serenity/packages/corelib",
"scripts": {
"build": "rollup -c && node build/build",
"test": "pnpm build && jest --coverage",
"build": "node build/build",
"doc": "typedoc --plugin typedoc-plugin-markdown --exclude **/lib/**/* --excludePrivate --readme none --githubPages false --sourceLinkTemplate https://github.com/serenity-is/serenity/blob/master/{path}#L{line} --out /Sandbox/serenity-is/SerenityIs/SerenityIs.Web/Docs/api/js/corelib --json ./out/typedoc.json src",
"dts": "rollup -c",
"jest": "jest",
"tsc": "tsc",
"doc": "typedoc --plugin typedoc-plugin-markdown --exclude **/lib/**/* --excludePrivate --readme none --githubPages false --sourceLinkTemplate https://github.com/serenity-is/serenity/blob/master/{path}#L{line} --out /Sandbox/serenity-is/SerenityIs/SerenityIs.Web/Docs/api/js/corelib --json ./out/typedoc.json src"
"prepublishOnly": "npm run build && npm run jest && npm run dts",
"test": "npm run build && jest --coverage",
"tsc": "tsc"
},
"type": "module"
}
144 changes: 18 additions & 126 deletions packages/corelib/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,129 +1,21 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import { basename, resolve } from "path";
import { dts } from "rollup-plugin-dts";
import { minify } from "terser";
import fs from 'fs';
import sourcemapsPlugin from './build/rollup-sourcemaps.js';
import typescript from '@rollup/plugin-typescript';

var externalPackages = ["@serenity-is/sleekgrid"];

var globals = {
'flatpickr': 'flatpickr',
'@serenity-is/sleekgrid': 'this.Slick = this.Slick || {}'
}

async function minifyScript(fileName) {
var minified = await minify({ [basename(fileName)]: fs.readFileSync(fileName, 'utf8') }, {
mangle: true,
sourceMap: {
content: fs.existsSync(fileName + '.map') ? fs.readFileSync(fileName + '.map', 'utf8') : undefined,
filename: fileName.replace(/\.js$/, '.min.js').replace(/\.\/out\//g, ''),
url: fileName.replace(/\.js$/, '.min.js.map').replace(/\.\/out\//g, '')
},
format: {
beautify: false,
max_line_len: 1000
}
});
fs.writeFileSync(fileName.replace(/\.js$/, '.min.js'), minified.code);
fs.writeFileSync(fileName.replace(/\.js$/, '.min.js.map'), minified.map);
}

const nodeResolvePlugin = () => nodeResolve({
resolveOnly: ['@serenity-is/base', '@serenity-is/base-ui', 'jsx-dom']
});

export default [
{
input: "src/index.ts",
output: [
{
file: './out/index.global.js',
format: "iife",
sourcemap: true,
sourcemapExcludeSources: false,
name: "Serenity",
generatedCode: 'es2015',
extend: true,
freeze: false,
footer: `(function (me) {
if (!me.Q)
me.Q = me.Serenity;
else if (me.Q !== me.Serenity) {
Object.keys(me.Q).forEach(function(key) {
if (me.Q[key] != null &&
me.Serenity[key] == null) {
me.Serenity[key] = me.Q[key];
}
});
me.Q = me.Serenity;
}
me.Slick = me.Slick || {};
['Aggregators', 'AggregateFormatting'].forEach(function(x) {
me.Slick[x] = me.Slick[x] || {};
Object.assign(me.Slick[x], Serenity[x]);
});
['RemoteView'].forEach(function(x) {
me.Slick[x] = Serenity[x];
});
})(this);`,
globals
}
],
plugins: [
nodeResolvePlugin(),
typescript({
tsconfig: 'tsconfig.json',
resolveJsonModule: true,
outDir: './out',
sourceRoot: resolve('./corelib'),
exclude: ["**/*.spec.ts", "**/*.spec.tsx"],
}),
sourcemapsPlugin()
],
external: externalPackages
},
{
input: "./out/index.d.ts",
output: [{
file: "./out/index.bundle.d.ts",
format: "es"
}],
plugins: [
nodeResolvePlugin(),
dts({
respectExternal: true
}),
{
name: 'writeFinal',
writeBundle: {
sequential: true,
order: 'post',
async handler({ dir }) {
function writeIfDifferent(target, content) {
if (!fs.existsSync(target) ||
fs.readFileSync(target, 'utf8') != content) {
fs.writeFileSync(target, content);
}
}

function copyIfDifferent(source, target) {
writeIfDifferent(target, fs.readFileSync(source, 'utf8'));
}

!fs.existsSync('./dist') && fs.mkdirSync('./dist');
copyIfDifferent('./out/index.bundle.d.ts', './dist/index.d.ts');
!fs.existsSync('./wwwroot') && fs.mkdirSync('./wwwroot');
copyIfDifferent('./out/index.global.js', './wwwroot/index.global.js');
copyIfDifferent('./out/index.global.js.map', './wwwroot/index.global.js.map');
await minifyScript('./out/index.global.js');
copyIfDifferent('./out/index.global.min.js', './wwwroot/index.global.min.js');
copyIfDifferent('./out/index.global.min.js.map', './wwwroot/index.global.min.js.map');
}
}
}
],
external: externalPackages
}
];
export default [{
input: "./src/index.ts",
output: [{
file: "./dist/index.d.ts",
format: "es"
}],
plugins: [
nodeResolve({
resolveOnly: ['@serenity-is/base', '@serenity-is/base-ui', 'jsx-dom']
}),
dts({
respectExternal: true
})
],
external: [
"@serenity-is/sleekgrid"
]
}];
2 changes: 1 addition & 1 deletion packages/corelib/src/base/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export function isPromiseLike(obj: any): obj is PromiseLike<any> {
return obj instanceof Promise || ((typeof obj === "object" && obj != null && typeof obj.then === "function" && typeof obj.catch === "function"));
}

export type NoInfer<T> = [T][T extends any ? 0 : never];
export type SNoInfer<T> = [T][T extends any ? 0 : never];

export class EditorAttribute { }
registerClass(EditorAttribute, 'Serenity.EditorAttribute');
Expand Down
2 changes: 1 addition & 1 deletion packages/corelib/src/mocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { resolveServiceUrl } from "../base/services";

const root = resolve('./');

const nscorelibPath = "~/out/index.global.js";
const nscorelibPath = "~/wwwroot/index.global.js";

export function loadNSCorelib() {
loadExternalScripts(nscorelibPath);
Expand Down
4 changes: 2 additions & 2 deletions packages/corelib/src/ui/widgets/widgetutils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fluent, NoInfer, getInstanceType, getTypeFullName, isArrayLike, isAssignableFrom, notifyError } from "../../base";
import { Fluent, SNoInfer, getInstanceType, getTypeFullName, isArrayLike, isAssignableFrom, notifyError } from "../../base";

let elementMap: WeakMap<Element, { [key: string]: { domNode: HTMLElement } }> = new WeakMap();

Expand Down Expand Up @@ -124,4 +124,4 @@ export type WidgetProps<P> = {
id?: string;
class?: string;
element?: ((el: HTMLElement) => void) | HTMLElement | ArrayLike<HTMLElement> | string;
} & NoInfer<P>
} & SNoInfer<P>
Loading

0 comments on commit 1808751

Please sign in to comment.