Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perform replacement in one pass of the output #67

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

TikiTDO
Copy link
Contributor

@TikiTDO TikiTDO commented Jul 15, 2021

This changes the transform pass of the generator to run in one pass of the output string, instead of using string replacer. It might make sense to just make something like an applyTransformersToString, or whatever name you might like, and put it in a util file. If you have an opinion on where it should go I'd be happy to move it.

@TikiTDO TikiTDO force-pushed the feature/replacer branch 4 times, most recently from ed2c041 to 7813180 Compare July 15, 2021 02:39
Comment on lines 294 to 304
// Create a function to apply the transformations in one go
const regexEscape = (text: string) => text.replace(/([^a-zA-Z0-9_])/g, '\\$1');
const replacerLookup: Record<string, string> = {};
const replacerRegexBase = replacers
.map((replacer: IReplacer) => {
replacerLookup[replacer.slot] = replacer.slotValue;
return regexEscape(replacer.slot);
})
.join('|');
const replacerRegex = new RegExp(`^${replacerRegexBase}$`, 'g');
const replacer = (text: string) => text.replace(replacerRegex, (slot) => replacerLookup[slot]);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you trying to remove replace-string as a dependency and write you own code? I don't understand the benefit to adding this code over the three lines that is already there:

replacers.forEach((replacer: IReplacer) => {
  output = replaceString(output, replacer.slot, replacer.slotValue);
});

@TikiTDO
Copy link
Contributor Author

TikiTDO commented Jul 15, 2021

The issue with replaceString implementation is that it will have to go through the entire string once for every potential replacement token/case combination.

With the addition of the underline case values that means each string has to be iterated through 12 times for every single token. It's a few milliseconds for a small file with one or two tokens, but if you were trying to generate a really big template with a bunch of tokens it might actually start to matter.

The implementation above will iterate through the output string once, and replace each appropriate value as it finds it. It is 12 * # of Tokens times faster, minus the time to compile the regex, which should be trivial for a mostly static regex like this one.

@TikiTDO
Copy link
Contributor Author

TikiTDO commented Jul 15, 2021

For more concrete numbers, I did a test with three approaches. The simple | approach up above, a regex-trie implementation (with the downside of extra deps), and the original one from the code with a worst case, 25 replacer run, repeated 100,000 times. Results came out as follows:

trie tools/templates/react/component/__name__.module.scss: 88.985ms
simple tools/templates/react/component/__name__.module.scss: 46.941ms
orig tools/templates/react/component/__name__.module.scss: 641.433ms

trie tools/templates/react/component/__name__.spec.tsx: 97.956ms
simple tools/templates/react/component/__name__.spec.tsx: 154.666ms
orig tools/templates/react/component/__name__.spec.tsx: 1.104s

trie tools/templates/react/component/__name__.tsx: 90.612ms
simple tools/templates/react/component/__name__.tsx: 144.562ms
orig tools/templates/react/component/__name__.tsx: 1.127s

The trie is more effective when working with larger files, while the simple case rips through smaller files. Both were around 7-12x faster than the replaceString function for this use case. I'll commit both implementations so you can compare.

package.json Outdated
@@ -1,105 +0,0 @@
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to delete this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah whoa, how did that happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I restored the file if you wanted to play around with the 3 approaches. Looks like I deleted it instead of an package-lock.json while I was cleaning up.

@codeBelt
Copy link
Owner

Thanks for the insight why you are changing out replaceString. I want to look into this more but sadly I will away from my computer for the next two weeks. I will have to revisit this later.

@TikiTDO
Copy link
Contributor Author

TikiTDO commented Jul 15, 2021

No rush. The other two PRs were the really important ones. This one is just a performance optimization for super extreme edge cases. Really just idle work while I was waiting for a build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants