-
-
Notifications
You must be signed in to change notification settings - Fork 428
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
Duplicate Imports #145
Comments
@jhnns, I ran into the same issue. No doubt it is a problem of Sass in general, but I had thought the sass-loader was intercepting In any case, what is the recommended practice? Should I just be careful that no file is ever (As an aside, I would also be OK with , and see possible benefits of, ditching Sass in favor of some JavaScript-based stylesheet language like JSS, but I am worried there might be issues that I haven't thought of converting a Sass codebase to JSS, and I am concerned that there are a million different proposals for styling React right now, and JSS doesn't seem to have particularly separated itself from the crowd. Confusing times!) |
There are helper mixins like sass-import-once which prevents double imports. However, this requires you to wrap your whole code with curly braces and to find a unique id for your module (usually the file path within the project). Personally, I find that too annoying. After fiddling around with double imports I found out that it's not actually a big problem. Gziping your static assets eliminates code duplication very efficiently. You can try that out for your specific case by creating two versions: one with
Yes, that would be possible and I'm actually planing to do something. However, rubysass is going to ship this with If you are open to ditch Sass, I can also recommend LESS. I know, there are endless debates about Sass vs. LESS and in the end they are always pointless. However, there are two things LESS is actually handling better:
And in the end, Sass and LESS are very familiar. Actually, I'm using both in different projects and it's not a big deal. |
If you plan on doing StyleSheet-Per-Component (like @JoeStanton s example) Each sass file will compile to a self-contained entity. If you put anything that outputs in your common "variables.scss" it will duplicate. variables, functions, mixins and placeholder selectors don't output. However, placeholder selectors will not merge all extensions across components. Webpack isn't responsible for this... nor its loaders. Sass (in its current form) cannot handle this. The only way to make this work without duplication is to add a pre-step that synthesises a fake "main.scss" that imports all the components as partials... which also has its issues. I'm using the sass-per-component model and love it. I use the baggage loader to auto-import sass with my component files. (and the extract text plugin to merge into one css file) I've basically come to accept the limitation, but take comfort in knowing that each component is self-sustaining and can just be stamped... so duplicated styles become less and less of an issue because I should be defining local-to-component styles. I like @jhnns recommendation. Sass isn't the end-all-be-all tool. Less may be better suited for your task. |
Thanks, guys. Maybe I should have known, but I didn't realize I could avoid the duplication by just being careful to avoid importing anything that outputs. And gzip does seem like it can help out if something is still being duplicated. I will keep on with Sass and sass-loader for the time being. |
You can overcome this with https://github.com/at-import/node-sass-import-once - maybe for now, it's a special case until 4.0 comes out! |
Thx for sharing @kenotron 👍 |
I've had great success doing this:
|
@jsg2021 and how do you import |
@wzup I don't understand what you are asking? In the approach I mentioned, you would simply define your |
@kenotron I've had trouble with resolving |
I've tried node-sass-importer as suggested by @kenotron. Unfortunately, it seems to have issues with relative imports. We use local styles in our angular project, locating component styles next to the component's javascript. Inside the javascript we import the styles Some excerpts from the webpack config The sass loader should work in the scripts and styles directories: {
test: /\.scss$/, loader: 'style!css?-minimize!sass',
include: [
path.resolve(__dirname, 'app/scripts'),
path.resolve(__dirname, 'app/styles')
]
}, We inject the node-sass-importer. From taking a brief look at the sass-loader code, I think the webpack importer is still pushed on top of this? I.e. the importer reaching node-sass is sassConfig: {
importer: importer
}, Webpack should look in these places when resolving dependencies: resolve: {
root: [
path.resolve(__dirname, 'app/scripts'),
path.resolve(__dirname, 'app/icons'),
path.resolve(__dirname, 'bower_components'),
path.resolve(__dirname, 'app/styles/sass'),
path.resolve(__dirname, 'test')
],
} Our components all use some styles from our global brand stylesheets, so we need to import the global stylesheets for each component. This leads to a lot of style duplication and makes working with Safari's dev tools impossible. The browser just isn't able to handle all these duplicate rules. Any ideas on how to fix this? |
Nevermind, I found the issues were related to what we exactly imported in those shared chunks. Fixed it by optimizing that and ensuring we only import mixins, variables, etc. Thanks for this great loader! |
Hi @felixjung How did you exactly optimize that please ? |
@lauterry To clarify, he is insuring that SCSS files imported across multiple components only contain things like variables and mixins which don't actually turn into CSS output. Thus the final CSS output won't have duplicate styling in it. If you want to import non-variable or non-mixin styles for more than one component, it's more efficient to import that just once at a higher level component or just in a standard CSS file to avoid duplication. |
Thanks @mattaningram for the clarification ! |
I'm trying to add Normalize.css to my stylesheet, and to avoid duplications. I imported it in the high level component; however, it's at the bottom of the style cascade... I can't include a link to Normalize in my HTML because it's a node module. Also, I really only want one, compressed CSS file. Consider the following file structure:
App.js is an entry point like so:
Here is app.scss:
Depiction of the outputted bundle, or the "cascade." (I need Normalize on top):
|
@MatthewKosloski This was the exact issue I was having in addition to the duplicates, I couldn't find any way to set the import order of SCSS files. This became such a frustration I eventually stopped importing SCSS files in React components and just did it the "old fashioned" way in a big style.scss file which solved all my duplication and order issues, however loses the benefit of only loading the CSS needed for particular components. That being said the final CSS file gets cached, so it's not much of an impact to load times after the first time they load a page on your site. It also simplifies having to remember which SCSS files you need for each component. It would be nice if there was some way of setting a universal order priority for component imports, but that would mean one more thing to keep track of and update as you add new .scss files, so for now I'm happy with the traditional approach. |
@MatthewKosloski this issue is not about the ordering of rules, please don't change the topic. I assume that you are using the extract-text-webpack-plugin. In this case, the order of rules dependents on the order of |
For the record, unless I messed something up, sass-import-once does not work with the sass loader. It makes sense because the mixin provided by sass-import-once can't keep track of the imports for the specified module since the sass-loader has isolated contexts. |
Any update on this? Can't seem to get rid of those duplicates. |
While the original issue here is related to sass/less/stylus, a fix/hack/patch for this is to use the If you want to use this in dev, you will have to use a plugin like |
Related performance discussion: #296 (comment) |
@phun-ky You saved my day! I was encountering the same issue with my SCSS files included several times (9 in my case!) when components included their own dependencies and was really frustrated while searching for a solution to this. Then I tried |
Apparently there is no for this universal and good solution. If someone has an idea how we can to implementing this, i will be glad to see this here #296. |
Any ideas on how to get the node-sass-imported / sassConfig property to be recognized by Webpack 3? UPDATE: Webpack 3 entry should go within module.rules[X].loader.use[Y].options { importer: nodeSassImporter}
However, it isn't ignoring duplicates, still including them :( |
This should be supported by Because the Meanwhile maybe Please reopen this issue. |
@rw3iss original |
@evilebottnawi which |
Neither Imho both disqualify as a proper solution to the import-once problem. |
are there compile time/performance benefits to |
Of course their are, but the main point is... if you import duplicate files, say some file that has code you want to use in any number of components, and those imported files contain actual css (ie. real css, classes descriptors and their properties, etc), then that code will get rendered into the final bundle, and eventually make its way to the browser as well, and this file will have redundant CSS, and will result in a larger css bundle size, and will also take some bit of extra processing by the browser to be rendered. Obviously we only want to send what we need to to the browser. So, the main workaround for sass usage is to only put functional shared code in your shared files, and still import them just the same. That means only writing shared code as things like mixins, or functions, within sass. When you import files with mixins or functions, things that don't actually output any css by themselves, then only the sass engine uses them in its memory, to be used in the files that are importing them, and because of this, only those component's actual css makes it into the output bundle, but not the imported files css, because their isn't any actual real css in those files, with this approach. In short, if you had written actual css in the files you're importing, then that css would be written to the output bundle however many times the file is imported, but if your shared file only contains functional stuff, that code is only used by sass internally, and not rendered redundantly during every import. Hope that makes sense, but let me know if you need an example. |
@rw3iss thanks ryan this was the example i gave on stackoverflow https://stackoverflow.com/questions/58066851/does-removing-redundant-scss-imports-affect-compile-time in the example there, if variables.scss has a bunch of variables defined like if so and you answer there i will accept and upvote if you have stackoverflow account, thanks! |
#### Description of changes This PR fixes perf issues when trying to use Chromium's dev tools (particularly, the "inspect element" view) with our web extension. The issue was that every individual CSS module that imported `colors.scss` was resulting in its own copy of all the color variables being included in the final bundled css files (see webpack-contrib/sass-loader#145); `detailsview.css` had dozens of copies, each of which was being considered and then rendered as "overriden" in the dev tools UI for every element, which was causing lots of slowdown. This PR resolves that issue by splitting out the parts of `colors.scss` that define actual CSS `--var` statements from the parts that define the SCSS variables our modules use directly. The SCSS variables remain in place in `colors.scss` (so no change to most of the consumers is required), but the `--var` styles are moved into a separate `/common/styles/root-level-only/color-definitions.scss` file that is intended to be imported only by root-level scss files. I then updated the root-level SCSS files (covering popup/details view/guidance pages/injected/reports/ui package) to directly reference the new root-level-only `.scss`. I did a similar split for `common.scss`, though most of the actual perf issue came from `colors.scss`. I verified that there didn't seem to be any styling regressions in: * Injected page dialog or highlight boxes * Details view * Popup * Guidance pages * Generated reports (fastpass and assessment) * UI package * Unified #### Pull request checklist <!-- If a checklist item is not applicable to this change, write "n/a" in the checkbox --> - [x] Addresses an existing issue: #1503 - [x] Ran `yarn fastpass` - [n/a] Added/updated relevant unit test(s) (and ran `yarn test`) - [x] Verified code coverage for the changes made. Check coverage report at: `<rootDir>/test-results/unit/coverage` - [x] PR title *AND* final merge commit title both start with a semantic tag (`fix:`, `chore:`, `feat(feature-name):`, `refactor:`). See `CONTRIBUTING.md`. - [n/a] (UI changes only) Added screenshots/GIFs to description above - [n/a] (UI changes only) Verified usability with NVDA/JAWS
I know there has been plenty of discussion around this in #31, and it looks like the issue should have been 'resolved', but it's still happening for us.
Importing a stylesheet so we can benefit from mixins, extend styles etc. in our CSS modules causes the imported file to be included twice in the resulting output. This happens even if we use Webpack's
DedupePlugin
.components/a/a.scss:
components/b/b.scss:
Are we doing something wrong? Or is there a better way to solve this problem?
The text was updated successfully, but these errors were encountered: