build(core): improved tree-shakeability
This commit is contained in:
parent
56b2fe70d3
commit
42f1482d7f
5 changed files with 68 additions and 5 deletions
|
@ -1,4 +1,6 @@
|
||||||
module.exports = ({ path, transformFile, packageDir, outDir }) => ({
|
const KNOWN_DECORATORS = ['memoizeGetters', 'makeInspectable']
|
||||||
|
|
||||||
|
module.exports = ({ path, glob, transformFile, packageDir, outDir }) => ({
|
||||||
esmOnlyDirectives: true,
|
esmOnlyDirectives: true,
|
||||||
esmImportDirectives: true,
|
esmImportDirectives: true,
|
||||||
final() {
|
final() {
|
||||||
|
@ -7,5 +9,56 @@ module.exports = ({ path, transformFile, packageDir, outDir }) => ({
|
||||||
|
|
||||||
transformFile(path.join(outDir, 'cjs/network/network-manager.js'), replaceVersion)
|
transformFile(path.join(outDir, 'cjs/network/network-manager.js'), replaceVersion)
|
||||||
transformFile(path.join(outDir, 'esm/network/network-manager.js'), replaceVersion)
|
transformFile(path.join(outDir, 'esm/network/network-manager.js'), replaceVersion)
|
||||||
|
|
||||||
|
// make decorators properly tree-shakeable
|
||||||
|
// very fragile, but it works for now :D
|
||||||
|
const decoratorsRegex = new RegExp(
|
||||||
|
`(${KNOWN_DECORATORS.join('|')})\\((.+?)\\);`,
|
||||||
|
'gs',
|
||||||
|
)
|
||||||
|
|
||||||
|
const replaceDecorators = (content, file) => {
|
||||||
|
if (!KNOWN_DECORATORS.some((d) => content.includes(d))) return null
|
||||||
|
|
||||||
|
const countPerClass = new Map()
|
||||||
|
|
||||||
|
content = content.replace(decoratorsRegex, (_, name, args) => {
|
||||||
|
const [clsName_, ...rest] = args.split(',')
|
||||||
|
const clsName = clsName_.trim()
|
||||||
|
|
||||||
|
const count = (countPerClass.get(clsName) || 0) + 1
|
||||||
|
countPerClass.set(clsName, count)
|
||||||
|
|
||||||
|
const prevName = count === 1 ? clsName : `${clsName}$${count - 1}`
|
||||||
|
const localName = `${clsName}$${count}`
|
||||||
|
|
||||||
|
return `const ${localName} = /*#__PURE__*/${name}(${prevName}, ${rest.join(',')});`
|
||||||
|
})
|
||||||
|
|
||||||
|
if (countPerClass.size === 0) {
|
||||||
|
throw new Error('No decorator usages found, but known names were used')
|
||||||
|
}
|
||||||
|
|
||||||
|
const customExports = []
|
||||||
|
|
||||||
|
for (const [clsName, count] of countPerClass) {
|
||||||
|
const needle = new RegExp(`^export class(?= ${clsName} ({|extends ))`, 'm')
|
||||||
|
|
||||||
|
if (!content.match(needle)) {
|
||||||
|
throw new Error(`Class ${clsName} not found in ${file}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content.replace(needle, 'class')
|
||||||
|
customExports.push(
|
||||||
|
`export { ${clsName}$${count} as ${clsName} }`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return content + '\n' + customExports.join('\n') + '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const f of glob.sync(path.join(outDir, 'esm/highlevel/types/**/*.js'))) {
|
||||||
|
transformFile(f, replaceDecorators)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,7 +33,11 @@ function getAllGettersNames<T>(obj: T): (keyof T)[] {
|
||||||
* > (getter that caches after its first invocation is also
|
* > (getter that caches after its first invocation is also
|
||||||
* > considered pure in this case)
|
* > considered pure in this case)
|
||||||
*/
|
*/
|
||||||
export function makeInspectable<T>(obj: new (...args: any[]) => T, props?: (keyof T)[], hide?: (keyof T)[]): void {
|
export function makeInspectable<T>(
|
||||||
|
obj: new (...args: any[]) => T,
|
||||||
|
props?: (keyof T)[],
|
||||||
|
hide?: (keyof T)[],
|
||||||
|
): typeof obj {
|
||||||
const getters: (keyof T)[] = props ? props : []
|
const getters: (keyof T)[] = props ? props : []
|
||||||
|
|
||||||
for (const key of getAllGettersNames<T>(obj.prototype)) {
|
for (const key of getAllGettersNames<T>(obj.prototype)) {
|
||||||
|
@ -67,4 +71,6 @@ export function makeInspectable<T>(obj: new (...args: any[]) => T, props?: (keyo
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
obj.prototype[customInspectSymbol] = obj.prototype.toJSON
|
obj.prototype[customInspectSymbol] = obj.prototype.toJSON
|
||||||
|
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function memoizeGetters<T>(cls: new (...args: any[]) => T, fields: (keyof T)[]) {
|
export function memoizeGetters<T>(cls: new (...args: any[]) => T, fields: (keyof T)[]): typeof cls {
|
||||||
for (const field of fields) {
|
for (const field of fields) {
|
||||||
const desc = Object.getOwnPropertyDescriptor(cls.prototype, field)
|
const desc = Object.getOwnPropertyDescriptor(cls.prototype, field)
|
||||||
if (!desc) continue
|
if (!desc) continue
|
||||||
|
@ -25,4 +25,6 @@ export function memoizeGetters<T>(cls: new (...args: any[]) => T, fields: (keyof
|
||||||
configurable: true,
|
configurable: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return cls
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ function writeQuery(query: InputQuery) {
|
||||||
return `?${str}`
|
return `?${str}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deeplinkBuilder<T>(params: BuildDeeplinkOptions<T>): Deeplink<T> {
|
/* @__NO_SIDE_EFFECTS__ */ export function deeplinkBuilder<T>(params: BuildDeeplinkOptions<T>): Deeplink<T> {
|
||||||
const { internalBuild, internalParse, externalBuild, externalParse } = params
|
const { internalBuild, internalParse, externalBuild, externalParse } = params
|
||||||
|
|
||||||
const fn_ = (options: T & CommonDeeplinkOptions) => {
|
const fn_ = (options: T & CommonDeeplinkOptions) => {
|
||||||
|
|
|
@ -17,7 +17,8 @@ function exec(cmd, params) {
|
||||||
|
|
||||||
function transformFile(file, transform) {
|
function transformFile(file, transform) {
|
||||||
const content = fs.readFileSync(file, 'utf8')
|
const content = fs.readFileSync(file, 'utf8')
|
||||||
fs.writeFileSync(file, transform(content))
|
const res = transform(content, file)
|
||||||
|
if (res != null) fs.writeFileSync(file, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildConfig = {
|
const buildConfig = {
|
||||||
|
@ -44,6 +45,7 @@ const buildConfig = {
|
||||||
config = config({
|
config = config({
|
||||||
fs,
|
fs,
|
||||||
path,
|
path,
|
||||||
|
glob,
|
||||||
exec,
|
exec,
|
||||||
transformFile,
|
transformFile,
|
||||||
packageDir,
|
packageDir,
|
||||||
|
|
Loading…
Reference in a new issue