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
Improve performances #470
Improve performances #470
Conversation
Following styled-system#444, I bring perf improvements from @smooth-ui/system into styled-system. The goal is to make this library the best one and the universal one. What have changed? - I switched to the core of @smooth-ui/system, more performant especially with multiple compose. Composition is now flat, it means you can compose 10 times and it will not be slower. We are probably in O(n), where "n" is the number of props. - I splitted the logic in several files to make it clearer - I switched to rollup in order to optimize build, provide umd and improve tree shaking What are the breaking changes? - We now rely on the order of props. ES2015 is here and we can rely on it, see this tweet for context: https://twitter.com/ianstormtaylor/status/1115680037875752963. - We are more strict in breakpoints, we don't accept a non-existing breakpoint - We don't export utilities like get, themeGet, etc... - PropTypes are no longer included, they can be generated from meta - We don't return array, just an object with all props merged - Properties that default to pixels unit (like margin, padding) no longer include it
00ed38e
to
bbcd25e
Compare
package.json
Outdated
"module": "dist/index.esm.js", | ||
"main": "dist/styled-system.cjs.js", | ||
"module": "dist/styled-system.es.js", | ||
"jsnext:main": "dist/styled-system.es.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop jsnext:main
. It is deprecated for a long time.
package.json
Outdated
"main": "dist/index.cjs.js", | ||
"module": "dist/index.esm.js", | ||
"main": "dist/styled-system.cjs.js", | ||
"module": "dist/styled-system.es.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep esm
prefix. It's more descriptive. es
is often used to distribute es6 syntax.
rollup.config.js
Outdated
import babel from 'rollup-plugin-babel' | ||
import replace from 'rollup-plugin-replace' | ||
import commonjs from 'rollup-plugin-commonjs' | ||
import { uglify } from 'rollup-plugin-uglify' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use rollup-plugin-terser
. Terser is more stable.
rollup.config.js
Outdated
const esConfig = Object.assign({}, baseConfig, { | ||
output: { | ||
file: `${DIST_DIR}/${buildName}.es.js`, | ||
format: 'es', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
esm
format is an alias
external: [ | ||
...Object.keys(pkg.peerDependencies || {}), | ||
...Object.keys(pkg.dependencies || {}), | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
id => !id.startsWith('.') && !id.startsWith('/')
is more universal. It will treat as external @babel/runtime/...
. Make sure your config does this.
rollup.config.js
Outdated
}) | ||
|
||
const globals = { | ||
deepmerge: 'deepmerge', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would bundle this module for umd
@TrySound thanks! Done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to reuse parts of config instead of extending it over the place. Visually it becomes a bit simpler
https://github.com/istarkov/rifm/blob/master/rollup.config.js
rollup.config.js
Outdated
|
||
function getConfig() { | ||
const name = 'styledSystem' | ||
const buildName = 'styled-system' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pkg.name
rollup.config.js
Outdated
babel({ | ||
runtimeHelpers: true, | ||
exclude: 'node_modules/**', | ||
configFile: path.join(__dirname, 'babel.config.js'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Config file should work without option
rollup.config.js
Outdated
format: 'esm', | ||
}, | ||
external: id => !id.startsWith('.') && !id.startsWith('/'), | ||
plugins: [...baseConfig.plugins, resolve()], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why resolve plugin here? Only for index.js
?
rollup.config.js
Outdated
format: 'umd', | ||
globals, | ||
exports: 'named', | ||
sourcemap: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
globals is empty - can be removed, exports: named is autoselected since there is not default export, sourcemap is false by default.
rollup.config.js
Outdated
exports: 'named', | ||
sourcemap: false, | ||
}, | ||
external: Object.keys(globals), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All packages are bundled. Not necessary
babel.config.js
Outdated
presets: [['@babel/preset-env', { loose: true, modules: false }]], | ||
plugins: [ | ||
'babel-plugin-annotate-pure-calls', | ||
['@babel/transform-runtime', { useESModules: true }], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing is missing here. cjs bundle will get esm imports.
Here I added transform-runtime in place and didin't use it for tests and benchmarks. babel runtime is just an optimisation.
https://github.com/istarkov/rifm/blob/master/rollup.config.js#L19
@jxnblk is it OK for you if I switch the test engine to Jest? I had some difficulties with "ava" (watch mode + console logging is not nice). Also I have some unactivated tests that I could activate if I switch. Also could you please configure Travis to report the test status of this PR? |
@jxnblk and of course, I would like to have your advice on breaking changes. |
rollup.config.js
Outdated
const getBabelOptions = ({ useESModules }) => ({ | ||
exclude: '**/node_modules/**', | ||
runtimeHelpers: true, | ||
presets: [['@babel/preset-env', { loose: true, modules: false }]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may remove this line since env plugin has always modules: true
with rollup-plugin-babel.
Why have you stopped exporting Sure I can just import the theme object, but that doesn’t work for dynamic themes. |
Yeah same on the |
🙌 Thanks for this! I think some of the core performance improvements are looking good, and I'll follow up with a few inline questions to get a better sense of what these changes entail. Specifically, the new compose looks great! I do have a few thoughts and questions, so please bear with me. I was hoping that some of these performance improvements could be introduced without breaking changes (I think it might still be possible), but I'm also open to using this as a starting point for the next major v5. If possible, we could introduce some of the performance changes in v4, but use the current state of this PR as a potential end-state for v5. Notes
This was an experimental change from v3 to v4. In some benchmarks it looked like letting Emotion handle the merging and flattening of styles on its own was faster than merging them in Styled System when the two libraries were used together. That said, and in light of JSS looking to support Styled System, I think this change definitely should be addressed in v4, and I'm planning on opening a PR for this. See this issue for more: #471
This may no longer be the case, but converting numbers to pixels was previously required for Styled Components support. Can you confirm that this works with Styled Components? Questions
Can you elaborate on what this means with a code usage example? It looks like this only affects the plain object values?
Not sure I understand. Can you please elaborate? Is this the same as above? Requested Changes There are a few changes in here that I'd ask you to decouple from the core performance improvement since they are not really related and can be addressed as separate PRs. I'm more than happy to jump in to help break this up if you don't have much time to work on it.
Should this be a breaking change? As for whether or not this should be a breaking change, I'm open to discussion and can open a separate issue to track v5. Generally for v5, I was planning on splitting a lot of this up into a monorepo with Yarn workspaces and Lerna. If you think it's worth getting this in as a minor/non-breaking change, I think the following would need to be addressed:
If merging this as a non-breaking change isn't easy, let's start working towards a v5 release with a good migration plan. And again, thanks for all your work on this so far! |
I don't see a good reason to switch to Jest here. Ava is nice for simple libraries like this, and I prefer to use it when React and/or DOM APIs are not required. Totally open to changing this separately, but it seems out of scope for this change. To run Ava in verbose watch mode you can use
I'll look into what's happening here |
It looks like Travis wasn't reconfigured after moving this to the |
Hello @jxnblk, Thanks for your insights! I will answer your points:
I think it is possible to avoid all breaking changes, except props ordering. I think it is not really a breaking change, so we could release it as v4.x. Notes
I think it is better to merge styles in styled-system. It is optimized and for me it is not a breaking change.
I confirm it is working for styled-components, code is cleaner and faster.
On this specific point, I think we should ignore a non-existing breakpoint, I will adapt the code to just ignore non-defined breakpoint.
Today, you don't define the breakpoint
Yeah we could keep everything in the same file, it is not a problem, I can change the code. About Rollup, I think we should use it, it will result in a better build, and for me it is part from the performance part. So are you OK to keep Rollup (especially because it was reviewed by @TrySound and the config is rock solid!).
I added them in this PR to show the perf improvements, of course we could remove them from this PR before merging it. It could be interesting to put them in another repo, yes.
I will let the
Yeah, I will all documented utilities to avoid breaking change.
Strictly, it is but I think users don't define
As answered before, I will make it work as it work today to avoid breaking change. About JestI will definitely not make the change in that PR, it is not the subject. But I think it is better to switch to Jest instead of ava for several reason:
So I think it would be a good move (also for contributors) to move to Jest. Anyway it is another subject and it should be discussed in another issue. I will open a new one after this one will be done, one subject at a time. ConclusionI will work on the PR and operates these changes:
Are you OK with these changes? |
@neoziro Awesome! Sounds like we're mostly on the same page :) I'll start a v5 roadmap issue to track some of the changes discussed here, and lets figure out how to get this in as a minor change.
This too could be considered a breaking change, but might not affect how most people use this library. Probably need to think on this (don't make any changes yet), but it might be something to shim for a non-breaking change.
I think so... It could be helpful to look at a unit test or example that demonstrates what's different – think this is also useful for the changelog Otherwise, yeah this is looking great! Thanks for working on this! |
Just a heads up that it looks like unitless pixel value support was only recently added to Styled Components, so I think that should be treated as a breaking change styled-components/styled-components#2173 |
- Put all in a single file: `src/index.js` - Remove all breaking changes
Codecov Report
@@ Coverage Diff @@
## master #470 +/- ##
==========================================
- Coverage 100% 98.17% -1.83%
==========================================
Files 1 1
Lines 159 219 +60
==========================================
+ Hits 159 215 +56
- Misses 0 4 +4
Continue to review full report at Codecov.
|
1 similar comment
Codecov Report
@@ Coverage Diff @@
## master #470 +/- ##
==========================================
- Coverage 100% 98.17% -1.83%
==========================================
Files 1 1
Lines 159 219 +60
==========================================
+ Hits 159 215 +56
- Misses 0 4 +4
Continue to review full report at Codecov.
|
I updated the issue, so we have only two breaking changes:
I think these breaking changes are very small and not "real breaking change" for community. What do you think? I let the Rollup config in this PR, I don't have time to decouple it. Thanks! |
Awesome! Looking great! I'll take a closer look at this in a bit.
I'm guessing it's fine, but I'll take a closer look at the tests and see if there's anything that looks actually breaking
No worries, I can split that off into a separate branch later. I'm not sure what's missing coverage in the tests, but would be nice to keep it at 100%. Don't worry about it for now though – there might be some other changes before merging this in |
_: '100%', | ||
2: '50%', | ||
0: '100%', | ||
1: '50%', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test above was for showing how breakpoints could be "skipped" – why did you change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In your previous example it was not skipped, so there was a bug.
https://github.com/styled-system/styled-system/blob/master/test/index.js#L128
It is now fixed, if the key does not point to anything it will be skipped.
backgroundColor: '#111', | ||
}) | ||
}) | ||
// Impossible to ensure, due to perf issues |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that the last prop defined now trumps (i.e. object order)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah exactly, the last property defined on the object will won. It is very predictable and easy to fix.
export const createMediaQuery = n => `@media screen and (min-width: ${px(n)})` | ||
function getThemeValue(theme, path, initial) { | ||
if (!theme) return undefined | ||
return callOrReturn(get(initial || theme, path, undefined), { theme }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to support new functionality?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it is a new feature (you can release it hidden for now), it permits to have reference values in theme.
const theme = {
red: 'red',
primary: ({ theme }) => theme.red,
}
key: 'space', | ||
transformValue: getSpace, | ||
scale: spaceScale, | ||
transformValue: scale(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this called here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The transformValue
function is now much more permissive than before, so we can even implement the all space
logic in it.
scale()
is a transform function factory that gives this possibility. It is a factory because of fontSize
that has a custom scale
.
Gave you some merge conflicts :) I think this branch should help clear them up https://github.com/styled-system/styled-system/tree/smooth-merge-master |
Following #444, I bring perf improvements from @smooth-ui/system into styled-system.
The goal is to make this library the best one and the universal one.
What has changed?
especially with multiple compose. Composition is now flat, it means you
can compose 10 times and it will not be slower. We are probably in O(n),
where "n" is the number of props.
improve tree shaking
What are the breaking changes?
it, see this tweet for context: https://twitter.com/ianstormtaylor/status/1115680037875752963.
breakpoint
longer include it
0
if you want it to beBenchmarks
I added a benchmark in the project, the result: