Skip to content

Commit

Permalink
Use more efficient loops for const bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Sep 16, 2021
1 parent b7a3933 commit ef109d1
Show file tree
Hide file tree
Showing 41 changed files with 132 additions and 92 deletions.
35 changes: 30 additions & 5 deletions docs/999-big-list-of-options.md
Expand Up @@ -473,7 +473,36 @@ Whether to use arrow functions for auto-generated code snippets. Note that in ce

**output.generatedCode.constBindings**<br> Type: `boolean`<br> CLI: `--generatedCode.constBindings`/`--no-generatedCode.constBindings`<br> Default: `false`

This will use `const` instead of `var` in certain places and helper functions. Depending on the engine, this can provide [marginally better performance](https://benediktmeurer.de/2017/06/29/javascript-optimization-patterns-part2) in optimized machine code.
This will use `const` instead of `var` in certain places and helper functions. Depending on the engine, this can provide [marginally better performance](https://benediktmeurer.de/2017/06/29/javascript-optimization-patterns-part2) in optimized machine code. It will also allow Rollup to generate more efficient helpers due to block scoping.

```js
// input
export * from 'external';

// cjs output with constBindings: false
var external = require('external');

Object.keys(external).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k))
Object.defineProperty(exports, k, {
enumerable: true,
get: function () {
return external[k];
}
});
});

// cjs output with constBindings: true
const external = require('external');

for (const k in external) {
if (k !== 'default' && !exports.hasOwnProperty(k))
Object.defineProperty(exports, k, {
enumerable: true,
get: () => external[k]
});
}
```

**output.generatedCode.objectShorthand**<br> Type: `boolean`<br> CLI: `--generatedCode.objectShorthand`/`--no-generatedCode.objectShorthand`<br> Default: `false`

Expand Down Expand Up @@ -1346,8 +1375,6 @@ Example:
export { x } from 'external';

// CJS output with externalLiveBindings: true
('use strict');

Object.defineProperty(exports, '__esModule', { value: true });

var external = require('external');
Expand All @@ -1360,8 +1387,6 @@ Object.defineProperty(exports, 'x', {
});

// CJS output with externalLiveBindings: false
('use strict');

Object.defineProperty(exports, '__esModule', { value: true });

var external = require('external');
Expand Down
17 changes: 10 additions & 7 deletions src/finalisers/shared/getExportBlock.ts
Expand Up @@ -14,12 +14,13 @@ export function getExportBlock(
interop: GetInterop,
{
_,
s,
cnst,
directReturnFunctionRight,
getDirectReturnFunctionLeft,
getFunctionIntro,
getPropertyAccess,
n
n,
s
}: GenerateCodeSnippets,
t: string,
externalLiveBindings: boolean,
Expand Down Expand Up @@ -98,12 +99,14 @@ export function getExportBlock(
name: null
})}${name}[k]${directReturnFunctionRight}${n}${t}})`
: `exports[k]${_}=${_}${name}[k]`;
const copyPropertyIfNecessary = `{${n}${t}if${_}(k${_}!==${_}'default'${_}&&${_}!exports.hasOwnProperty(k))${_}${defineProperty}${s}${n}}`;
exportBlock +=
`Object.keys(${name}).forEach(${getFunctionIntro(['k'], {
isAsync: false,
name: null
})}{${n}` +
`${t}if${_}(k${_}!==${_}'default'${_}&&${_}!exports.hasOwnProperty(k))${_}${defineProperty}${s}${n}});`;
cnst === 'var' && specifier.needsLiveBinding
? `Object.keys(${name}).forEach(${getFunctionIntro(['k'], {
isAsync: false,
name: null
})}${copyPropertyIfNecessary});`
: `for${_}(${cnst} k in ${name})${_}${copyPropertyIfNecessary}`;
}
}
}
Expand Down
36 changes: 24 additions & 12 deletions src/utils/interopHelpers.ts
Expand Up @@ -153,6 +153,7 @@ const HELPER_GENERATORS: {
[MERGE_NAMESPACES_VARIABLE](t, snippets, liveBindings, freeze) {
const { _, directReturnFunctionRight, getDirectReturnFunctionLeft, getFunctionIntro, n } =
snippets;
// TODO Lukas use more efficient loops if we can use const
return (
`function ${MERGE_NAMESPACES_VARIABLE}(n, m)${_}{${n}` +
`${t}m.forEach(${getDirectReturnFunctionLeft(['e'], {
Expand Down Expand Up @@ -186,30 +187,41 @@ const createNamespaceObject = (
freeze: boolean,
namespaceToStringTag: boolean
) => {
const { _, cnst, getFunctionIntro, getPropertyAccess, n } = snippets;
const { _, cnst, getPropertyAccess, n, s } = snippets;
const copyProperty =
`{${n}` +
(liveBindings ? copyNonDefaultPropertyLiveBinding : copyPropertyStatic)(
t,
i + t + t,
snippets
) +
`${i}${t}}`;
return (
`${i}${cnst} n${_}=${_}${
namespaceToStringTag
? `{__proto__:${_}null,${_}[Symbol.toStringTag]:${_}'Module'}`
: 'Object.create(null)'
};${n}` +
`${i}if${_}(e)${_}{${n}` +
`${i}${t}Object.keys(e).forEach(${getFunctionIntro(['k'], {
isAsync: false,
name: null
})}{${n}` +
(liveBindings ? copyNonDefaultPropertyLiveBinding : copyPropertyStatic)(
t,
i + t + t,
snippets
) +
`${i}${t}});${n}` +
`${i}${t}${loopOverKeys(copyProperty, !liveBindings, snippets)}${n}` +
`${i}}${n}` +
`${i}n${getPropertyAccess('default')}${_}=${_}e;${n}` +
`${i}return ${getFrozen('n', freeze)};${n}`
`${i}return ${getFrozen('n', freeze)}${s}${n}`
);
};

const loopOverKeys = (
body: string,
allowVarLoopVariable: boolean,
{ _, cnst, getFunctionIntro, s }: GenerateCodeSnippets
) =>
cnst !== 'var' || allowVarLoopVariable
? `for${_}(${cnst} k in e)${_}${body}`
: `Object.keys(e).forEach(${getFunctionIntro(['k'], {
isAsync: false,
name: null
})}${body})${s}`;

const copyNonDefaultPropertyLiveBinding = (
t: string,
i: string,
Expand Down
Expand Up @@ -9,9 +9,9 @@ function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
for (var k in e) {
n[k] = e[k];
});
}
}
n["default"] = e;
return Object.freeze(n);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ef109d1

Please sign in to comment.