Closed SpawnAtis closed 1 year ago
Currently, I have a bunch of circular decencies in the project. When I fix one the build time decreases on 10-20 sec.
I would fix this first, then do perf evaluation. circular deps are highway to hell
So similar issue here (not related to version I guess).
We extracted common styles to styles
package within monorepo. now all components use this as a reference when defining styles via css
.
import {css} from 'linaria'
import {theme} from '@twisto/styles'
const root = css`
color: theme.primary;
`
This change increases storybook build from 60 seconds to 340 seconds. 🥺 🤒
I fixed all circular deps, it reduced time on 30 sec. Now, with linaria 1.3.0 - 1.46m, after upgrade to 1.3.1 - 4.75. 😞
I feel your pain... we are facing similar issues like mentioned above... had to redo whole building pipeline to make it usable....
Having the same Problem with high build times. The 1.3.0 start time (storybook) is at 2.35min
goes up by a half a minute to 3.02 min
. We do not have circular dependencies. The github actions build step is at around 5-7min.
- this is a medium / small sized project.
Any suggestions @Hotell how to make this more usable? I don't mind long build times in the CI but the hot reload speed is (depending on the widget I'm working) from 1sec
to 45sec
- which is too slow for a sane developer experience 😄
Where are the bottlenecks within linaria ? And how do other css in js frameworks compare ?
Sorry there have been a lot of holidays recently. I think we can improve the build time by implementing some sort of caching. I'll look into it soon.
Having a lot of issues with build times too. Is Linaria not ready yet for real use of styled
composition?
I removed all these const Container = styled(LayoutContainer)<LayoutContainerProps>'...';
in our project and replaced them with const Container = css'...';
. Then i used this as a className for <LayoutContainer className={Container} />
css' && { } '
to overwrite the default css It was a bunch of work and not easy in every case. Nevertheless you should fix that bug
@kaiserkoenig curious about 3, can you expand?
sure... if your CSSinJS or Linaria looks like this
const MyDiv = styled.div' background-color: black; '
and
const myAdvancedStyles = css' && { background-color: pink; } '
the builded CSS will be .myAdvancedStyles.myAdvancedStyles {background-color: pink;}
.
if you add this <MyDiv className={myAdvancedStyles} />
Mydiv
will be pink.
In most cases this is not necessary, but sometimes, especially when you get className
from different, interleaved components, a &&
is the new !important
;)
:wave: Thank you for writing and maintaining this library! Anything we could do to help facilitate the solution to this issue? I am faced with very long HMR times (6s) in quite a small project. As I add more styles, it will continue to get worse and it's already pretty much unusable (we are spoiled, I know :slightly_smiling_face: ).
I have noticed that you had a branch for in-memory builds here: https://github.com/callstack/linaria/commit/4c449ac0424c6aae630b238d3450b39b006e3d0d
What was the problem with it, it did not give the satisfying speedups?
another numbers, when used with storybook (no plugins, no stories loaded):
1.73 min
13s
Thank you for your feedback! 🙌 We're currently working on TS migration which is blocker for us (#398), but it's almost ready. After that we can work on optimizations.
@OriginalEXE if you want to contribute the best way would be creating a proposal issue with info about how do you want to solve this problem. If it will be a good idea, then we can guide you through development process. 😃
It would be great if you could share with us some repro that has extremely slow building process. 🐌
Thanks for using linaria and your patience! We'll make it better for you.
Those are the build speeds from emotion
vs linaria
for the same project. I just sed
the import for now.
╭───────────────────────────────────────────────────╮
│ │
│ Storybook 5.0.11 started │
│ 2.35 min for manager and 2.38 min for preview │
│ │
│ Local: http://localhost:9001/ │
│ On your network: http://192.168.1.205:9001/ │
│ │
╰───────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────╮
│ │
│ Storybook 5.0.11 started │
│ 19 s for manager and 20 s for preview │
│ │
│ Local: http://localhost:9001/ │
│ On your network: http://192.168.1.205:9001/ │
│ │
╰───────────────────────────────────────────────────╯
we have similar results ( as we're adding more components ):
linaria -> 4 minutes emotion -> 16 sec
Quick/Dirty fix:
For development purposes we are using emotion with webpack aliases. for production build we switch back to linaria. 💣🚨
@Hotell that is also what I'm implementing right now - best of both worlds
😄
Edit: Would be nice to have the same dev performance in linaria though
@steffenmllr just a headsup. You might experience various css bugs, as emotion is injecting classes in unpredictable order within <head/>
, which causes specificity issues !
quick fix:
const error = css`
&& {
color: theme.palette.red
}`
This is pretty serious issue and seems to be introduced by these 2 commits: 15986c8, 96b8284. We'd appreciate help in investigating which one is exactly to blame and, if both are, how they affect the build times separately. That should make it easier to focus on a quick fix for that.
Could you test your projects with our new alpha release? Let me know if build time improved.
Is there any improvement? :)
@pbitkowski just ran the build command, didn't test the output:
"linaria": "1.3.0", > 146.4s
"linaria": "1.3.1" > 138.3s
"linaria": "1.4.0-alpha.1", > 31.3s
@pbitkowski "linaria": "1.3.1" > 2.78 "linaria": "1.4.0-alpha.1", > 47.8s 👍
But I got an error :
import * as theme from '../../theme';
I think it is connected with syntax : import * as content from './somepath'
demo to reproduce: click. Just restart the sandbox and look at terminal.
loader problem 🤔 ?
Small frontend, 43 linaria components across 15 files.
Build times definitely improved in 1.4.0-alpha.1, though interestingly my production build is a lot faster than the development build (both builds include source maps)
Development build:
Production build:
My production build time has reached almost 10 minutes and I had some investigation today.
The reason why linaria is going to slow down is "core-js" in my case because linaria loader does:
So it spent a lot of times for a few packages like core-js, polished, which have many sub-packages.
Traced log on a very simple component code:
loader
file: /home/comet/Workspace/src/github.com/.../src/components/sections/...
transform.js
parse: 10.765ms
transformFromAst: 7013.279ms
babel/evaluate.js
resolve: 0.351ms
evaluate: 1056.369ms
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/...node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/e
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/_
... many many many more core-js deps
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/e
/home/comet/Workspace/src/github.com/.../node_modules/core-js/modules/e
/home/comet/Workspace/src/github.com/.../node_modules/stylis/stylis.js:
/home/comet/Workspace/src/github.com/.../node_modules/object-assign/ind
/home/comet/Workspace/src/github.com/.../node_modules/prop-types/lib/Re
/home/comet/Workspace/src/github.com/.../node_modules/prop-types/checkP
/home/comet/Workspace/src/github.com/.../node_modules/react/cjs/react.d
/home/comet/Workspace/src/github.com/.../node_modules/react/index.js:
/home/comet/Workspace/src/github.com/.../node_modules/join-react-contex
/home/comet/Workspace/src/github.com/.../src/utils/screen.ts: 116.451ms
/home/comet/Workspace/src/github.com/.../src/utils/css.ts: 1020.203ms
/home/comet/Workspace/src/github.com/.../src/components/sections/Footer
babel/evaluate.js
resolve: 0.373ms
evaluate: 1168.315ms
...same pattern here
babel/evaluate.js
resolve: 0.422ms
evaluate: 1300.890ms
...same pattern here
babel/evaluate.js
resolve: 0.284ms
evaluate: 1480.975ms
...same pattern here
babel/evaluate.js
resolve: 0.341ms
evaluate: 1620.540ms
...same pattern here
preprocessor: 2.812ms
Quick fix: Install this script in your postinstall to enable module cache
const { readFileSync, writeFileSync } = require('fs');
const filePath = require.resolve('linaria/lib/babel/extract');
const original = readFileSync(filePath, 'utf-8');
writeFileSync(filePath, original.replace(/\.invalidate\(\)/g, ''), 'utf-8')
Before this fix:
After fix:
stage | Before(ms) | After(ms) |
---|---|---|
Initial build | ~249000 | ~11000 |
HMR | ~41500 | ~900 |
And this is proportional to the product of the number of css tags used and the number of dependencies in the file.
Fortunately, there was no effect in my production without having to invalidate dependencies.
Even after disabling the invalidate as suggested by @cometkim, HMR updates are extremely slow at 30seconds with the latest develop branch. This makes development less enjoyable and productive. Hopefully the cause can be found. @cometkim how did you generate that trace log?
It was manually inserted using console.time()
and console.timeEnd()
.
@brandonkal is there no speed improvements after disabling invalidation? actually I'm enjoying the pretty fast HMR after that, so I'm not sure something there another cause or just bundle size is still matter.
Could you check again the Module.invalidate()
is not being called by your node_modules/linaria/lib/babel/extract
or share reproduce/trace?
@brandonkal FYI, It was tested on v1.3.1, probably v1.4.0-alpha or develop has different
@cometkim Thank you! I found that I had commented out the invalidate() in the enter() but not in exit(). HMR is now down to ~1-2 seconds. Before it was running the length of the whole build.
It looks like this works because the cache is only kept in memory and so it will be cleared whenever a production build finishes.
@satya164 I am curious on your reasons for calling Module.invalidate() on enter and exit. Removing those lines improved performance significantly without issue when using webpack to bundle things.
Discovered another inefficiency that causes things to be slow. Documenting it here in case someone is investigating.
The shaker will shake the current file, but after that, there is no restraint. Imported dependencies are resolved, transformed by babel, and evaluated. This is problematic depending on how you structure your code. Also if babel adds polyfills during the transform, those will be evaluated.
If you access all your components through an index file, your entire component library will be transpiled several times for each input file.
Example: Current file being parsed by webpack loader:
import { Button } from 'components'
const Hero = styled.section`
${Button} {
color: red;
}
}
index.tsx aliased as components
export * from 'buttons'
export * from 'utils'
export * from 'bigThing'
//...
All files are evaluated. The transforms are not cached. This complete evaluation process repeats for every file that the webpack loader receives.
I am working on solving these problems in my fork which is already 100+ commits ahead. I have some ideas on how to improve caching. Fixing these issues should bring the initial build time down.
@brandonkal any progress on your fork solving the issue when using an index.ts for exporting components?
@hemlok Yes, thank you for the interest I am seeing much faster compilation times with the changes. Currently working on documenting what I've changed locally and hope to push a release to GitHub soon.
For anyone still struggling with this, I was able to dramatically reduce rebuild times on 1.3.1 from 70s to around 1-5s by using cache-loader
to cache the results of a babel-loader
step that feeds into the linaria/loader
step. Unfortunately, initial build times are still slow with 90% of time spent in the linaria/loader step...
@brandonkal Your fork looks awesome! One question: can I keep the same usage of Linaria in my app? I'm using Linaria in over 141 files, so as you can imagine, updating the syntax would be painful.
For example, can I still use this syntax for passing props, and using a custom theme:
Creating element
<Nav disabled={selectedStepIndex === 0} id="howItWorksLeftArrow" onClick={() => this.handleChangeSlide(false)}>
<ArrowLeftIcon classes={{ root: classes.navIconRoot }} />
</Nav>
Styling element
const Nav = withTheme(styled.div`
display: flex;
align-items: center;
justify-content: center;
margin: auto 0;
width: 100px;
height: 100px;
border-radius: 100rem;
transition: all 150ms ease-in;
cursor: ${props => (props.disabled ? 'default' : 'pointer')};
font-size: 72px;
background: ${props => (props.disabled ? props.theme.colors.grayPale : props.theme.colors.grayChip)};
color: ${props => (props.disabled ? props.theme.colors.grayChip : props.theme.colors.brandBlue)};
&:hover {
filter: ${props => (props.disabled ? '' : 'brightness(102%)')};
}
&:active {
filter: ${props => (props.disabled ? '' : 'brightness(105%)')};
}
@media (max-width: ${props => props.theme.breakpoints.lg}) {
display: none;
}
`);
I'd really love to use your fork, because my build takes forever.
Yes. You should be fine as the additional syntax I've added are just shortcuts. You can use the beta version now as it is stable. The webpack set up requires postcss in the pipeline. I am planning to push a version 3 with documentation on all that but it might be some time before that happens. Please open an issue with build time comparisons and any questions you end up with.
@brandonkal Cool, thanks! I actually just submitted an issue on your fork; it's not specific to your fork, but it's a feature request I'd like (or would like to know about if it's already there). My repo is large, and when I run webpack-dev-server, it gets bogged down at the linaria/loader stage, and doesn't advance. The css files are all generated as it should be, but it gives me an error that I've run out of memory.
My question is this: is there a way to disable Linaria from using any memory and instead just creating the files? If there's not, do you think this is a feature you could implement?
Just updated to 1.4.1-beta.1 and performance is much better. Are there any additional benefits gained by the other recommendations on this thread? Or do they constitute the changes in the beta?
Linaria is now on v5. There have not been any activity for years and the discussion does not feel relevant to the current state. Let's close this one.
Feel free to open new issues if you are facing problems 🐱
Environment
"linaria": "^1.3.1", "webpack": "^4.30", "@babel/cli": "^7.4.3", "@babel/core": "^7.4.3", @babel/node": "^7.2.2", "react": "^16.8.6",
Description
After migration to 1.3.1 from 1.3.0 the build time increased in 5 times 😢. After analyzing changes in 1.3.1. suspicion fell on babel/evaluate.js.
In our project we have many "Base" components that use Styling custom components with interpplations, f.e.
<LayoutContainer />
,<DisplayName />
,<Box />
e.c.The problem is when u create your custom components that based on a "Base" one and use interpolation, Prop based styles the evalute.js executes too many times, and this cause such result for build time ( on my opinion). I tried to output log in TaggedTemplateExpression.js
console.log(state.file.opts.filename)
:Only small part of the whole log Log.txt
Is this a bug or I am doing something wrong ? Thx
P.S. Currently, I have a bunch of circular decencies in the project. When I fix one the build time decreases on 10-20 sec. 🤔 Can it be a reason of the problem?
Reproducible Demo
babel.config webpack.dev.config.txt
linaria.config.js