Reputation: 30700
I'm hosting legacy React components in an Angular app using a method similar to this one. There are lots of React components to bring in. They all import their own CSS with JS module imports:
import "./Admin.css";
This means every component is responsible for importing its own stylesheet, which is great. If I could just get the compiler to be happy with this like it was in the React app, that would be the best possible outcome.
The problem is this doesn't work when the React component is hosted in Angular. Importing a CSS file this way breaks compilation:
X [ERROR] Could not resolve "./Admin.css"
src/app/components/react/Admin/Admin.tsx:3:7:
3 │ import "./Admin.css";
╵ ~~~~~~~~~~~~~
Instead, I have to use CSS imports to include the React component's stylesheet in the .scss file of the Angular host:
// Inside AdminHost.component.scss
@import '../../react/Admin/Admin';
This comes with a much bigger problem: Now that each React component isn't responsible for its own styles, I have to dig through all of Admin.tsx's child components and manually import all their stylesheets as above. Then their children, and so on. Even if a component is the child of several parents, I have to repeat this process every time unless I happen to remember all the stylesheets it needs. There are a lot of components in the project, so it's a ton of tree-walking.
I tried programmatically importing the CSS files with a helper function:
// sanitizer is injected by the Angular host
export function importCss(cssUrl: string, sanitizer: DomSanitizer) {
const head = document.getElementsByTagName('head')[0];
const style = document.createElement('link');
style.rel = 'stylesheet';
style.href = sanitizer.sanitize(SecurityContext.URL, cssUrl);
head.appendChild(style);
}
// inside Admin.tsx:
importCss("path/to/Admin.css");
You may have already spotted the problem: cssUrl
is a URL, not a relative file path. This means I can no longer import "./Admin.css"
. I have to use a URL, and that means Admin.css has to live in a static assets folder. I explored this a little before deciding it wouldn't save me any work.
My current approach is to use a convention. Whenever I bring over a React component, I use the following rules:
The advantage here is it saves a lot of repeated effort. The problem is it doesn't save enough. There's still a lot of pain and manual tree-walking. I'm hoping there's a better way.
import "./Admin.css"
line and play nicely with it. All my attempts to do this have failed. (I should say I'm just assuming this is from Angular's compiler, since it worked in the React app.)link
tag. Then Attempt 1 would work. I don't know how to do that, though.Upvotes: 3
Views: 356
Reputation: 96
We use your 3rd point from 'Ideas' to set CSS from API responses;
new Buffer.from('yourCssHere').toString('base64')
data:text/css;base64,
to your converted base64 buffer as data:text/css;base64,yourBase64Here
.getLink(){
const linkEl = document.createElement('link');
linkEl.setAttribute('rel', 'stylesheet');
document.head.appendChild(linkEl);
}
setStyle(dataFromApi) {
getLink().setAttribute('href',dataFromApi)
}
This sets your CSS from API response.
Hope this Helps!!!
Upvotes: 0
Reputation: 2166
in case you are using webpack, you should be able to make relative imports work like so:
1 ) npm install css-loader style-loader --save-dev
2 ) register css in webpack.config.js
(or webpack.partial.js
with builders)
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'], // Ensures CSS is bundled
},
],
},
};
3 ) enable custom webpack config in angular.json
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.partial.js"
}
}
}
}
Upvotes: 0