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

Linaria Webpack loader cause rebuild twice for each change #878

Closed
malash opened this issue Nov 30, 2021 · 4 comments
Closed

Linaria Webpack loader cause rebuild twice for each change #878

malash opened this issue Nov 30, 2021 · 4 comments
Labels
bug report 🦗 Issue is probably a bug, but it needs to be checked bundler: webpack 📦 Issue is related to webpack bundler cat: performance 🚀 Issue is related to performance needs: complete repro 🖥️ Issue need to have complete repro provided

Comments

@malash
Copy link
Contributor

malash commented Nov 30, 2021

Environment

  • Linaria version: 2.1.1 and 3.0.0-beta.13
  • Bundler (+ version): Webpack 5.64.4
  • Node.js version: 16.3.0
  • OS: macOS 12.0.1

Description

In current implement, linaria/loader output a temp .css file in .linaria-cache while processing the JavaScript sources, and then append a require('path/to/temp.linaria.css') statement to it. Because Webpack always watches all the dependent files, it notice that temp .css files are changed and should be rebuild.

For a modification in dev mode, you can find the Webpack outputs compiled successfully twice:

change a line of CSS in JS => recompile JS file => output temp CSS file => recompile CSS file

image

Solution

I believe inline matchResource could resolve this issue.

I'v created a temp bugfix here and it did works.

The conception of this solution is create a virtual .css file by inline match resource !=!.

For example,

// index.ts
const cls = css`
  color: red;
`;

is transformed to

const cls = 'hash here';

require('path/to/.linaria-cache/index.linaria.css!=!outputCssLoader?cssPath=path%2Fto%2F.linaria-cache%2Findex.linaria.css!index.ts');

For more clear, the request includes these parts:
[virtual css file name]!=![a custom loader to output css sources]?cssPath=[real css file path]![the js source file]

Then, the outputCssLoader read the real .css from its cssPath option and return the code as a virtual .css file ( the name before !=! ) to match the rules with /\.css$/ in webpack.config.js.

According to Webpack dependent resolving logics, the outputCssLoader will recompile each time the .js file changed, the watch mode should continue works.

Reproducible Demo

Full reproducible demo here:

Linaria 2: https://github.com/malash/linaria-issue-878
Linaria 3: https://github.com/malash/linaria-issue-878/tree/linaria-3

Reproduce steps

  1. Run yarn
  2. Run yarn start
  3. Un-comment/comment the line 9 in src/App.js

from

const Title = styled.h1`
  font-family: sans-serif;
  font-size: 48px;
  color: #f15f79;
  /* font-weight: bold; */
`;

to

const Title = styled.h1`
  font-family: sans-serif;
  font-size: 48px;
  color: #f15f79;
  font-weight: bold;
`;
  1. Watch Webpack's log, the Compiled successfully output twice, which means Webpack rebuild twice.

Temporary fix

Un-comment this line in webpack.config.js to fix the issue:

// { loader: require.resolve("./bugfix/replaceRequireRequestLoader") },
@malash malash added bug report 🦗 Issue is probably a bug, but it needs to be checked needs: complete repro 🖥️ Issue need to have complete repro provided needs: triage 🏷 Issue needs to be checked and prioritized labels Nov 30, 2021
@github-actions github-actions bot added bundler: webpack 📦 Issue is related to webpack bundler cat: performance 🚀 Issue is related to performance and removed needs: triage 🏷 Issue needs to be checked and prioritized labels Nov 30, 2021
@malash
Copy link
Contributor Author

malash commented Nov 30, 2021

For more context why this issue bother me, is because I'm developing a React-based project call GojiJS that use Linaria with Webpack as its CSS-in-JS solution ( docs ).

This project runs not on browser but on a react-native-like environment called Mini Program. So hot reload is disabled. Each time developers changed a file, it cost twice times to rebuild the app. Since the simulator watched the dist folder, the app always relaunch twice.

So I believe this could be a performance issue, and once fixed, all Linaria apps could benefit.

@Anber
Copy link
Collaborator

Anber commented Nov 30, 2021

Hi @malash!

Thank you for your report and for the suggested solution! Unfortunately, it seems like it breaks URLs in styles (eg. background: url("../img/logo.svg"). I'm trying to figure out, how to fix it.

@Anber
Copy link
Collaborator

Anber commented Nov 30, 2021

It looks too good to be true, but I slightly improved your suggestion and rewrote webpack loaders in a way how rollup loader was written: no css-files, only in-memory cache. And it works. No extra rebuilds, no problems with css-files and project roots, no transformations for URLs in CSS.

@Anber
Copy link
Collaborator

Anber commented Dec 1, 2021

Fixed in 2.2.0 and 3.0.0-beta.16

ntucker added a commit to ntucker/linaria that referenced this issue Feb 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug report 🦗 Issue is probably a bug, but it needs to be checked bundler: webpack 📦 Issue is related to webpack bundler cat: performance 🚀 Issue is related to performance needs: complete repro 🖥️ Issue need to have complete repro provided
Projects
None yet
Development

No branches or pull requests

2 participants