I am talking about a big web app that has jquery and bootstrap stuff init.
Part of rewriting this giant app using react and material UI, we are writing component by component. Things work fine in general as we make progress toward making this a react app soon.
Our problem:
When a new react component is loaded into the page, the existing (already loaded) react components will lose some or all styles.
We checked the new component load new style (classes) which are matching the names of existing classes for other already loaded components.
Ex:
As you can see, jss1, jss2, ... MuiCardHeader, MuiGrid, ... were also the names for the previously loaded components and now they are overwritten for the newly loaded component.
Packages.json:
webpack config:
Some component code: we are using make style and in some cases withstyle
Tried too much stuff. But nothing seems to work. On initial load, the map has all the correct material-ui stuff but as soon as I click on a marker and the popup component loads in. Now the map is messed up as some styles are overwritten.
How can we make it so that each component styles are named unique and never conflicts with other stuff?
I checked MUI docs and GitHub issues about kinda similar issue but nothing is working for us.
Any thoughts?
If I add:
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
const generateClassName1 = createGenerateClassName({
seed: 'App2',
});
my custom classes ( like root, mydivstyle) will have the prefix like app2-jss1-root, app2-jss2-mydivstyle, ...
but muiCard, MuiCardHeader, ... still being overwritten.
So after a few trial and error. I was able to solve this.
Basically we don't have a component tree path where you can could add a single class generator because of our app structure at this stage. We will soon have one.
The solution was to wrap every component like.
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
seed: 'anyprefix',
});
class ActivityContainer extends Component {
render() {
return (
<StylesProvider generateClassName={generateClassName}>
<componenet/>
</StylesProvider>
);
};
}
I had to do this on the container level, this way any component loaded in that container will inherit this prefix.
No more conflicting class names between components and can load them dynamically.
Not a great way but no other option at least in our case. It will leave more classes on the DOM.
Related
We have a project running with React + Material UI, now there is a request to render a certain component(use ComponentA below) by using Ionic(It's not a reasonable requirement however I only discuss from technical perspective here).
From Ionic offical documentation, I did below
install the #ionic/react and #ionic/react-router package
including below css in root component
/* Core CSS required for Ionic components to work properly */
import '#ionic/react/css/core.css';
/* Basic CSS for apps built with Ionic */
import '#ionic/react/css/normalize.css';
import '#ionic/react/css/structure.css';
import '#ionic/react/css/typography.css';
/* Optional CSS utils that can be commented out */
import '#ionic/react/css/padding.css';
import '#ionic/react/css/float-elements.css';
import '#ionic/react/css/text-alignment.css';
import '#ionic/react/css/text-transformation.css';
import '#ionic/react/css/flex-utils.css';
import '#ionic/react/css/display.css';
invoke setupIonicReact() in root component
replace material UI element with ionic element in ComponentA
But it does not work - blank page, and I have to comment out below line
import '#ionic/react/css/structure.css';
Now I can see ionic elements displayed however css styles not applied they look more like html input, button and etc.
I realise there is something wrong however I could not figure out what's the root cause, after searching a while I decide to move step 2)& 3) into that ComponentA. But, new problem coming - setupIonicReact() can not be invoked inside the component, I looked into it and it's pretty simply
export const setupIonicReact = (config: IonicConfig = {}) => {
/**
* By default Ionic Framework hides elements that
* are not hydrated, but in the CE build there is no
* hydration.
* TODO FW-2797: Remove when all integrations have been
* migrated to CE build.
*/
if (typeof (document as any) !== 'undefined') {
document.documentElement.classList.add('ion-ce');
}
initialize({
...config
});
so, I make a simple change - like below
<div className="ion-ce">
<ComponentA />
</div>
now, my chrome keeps loading and there is a blank page alway.
So, I want to stop now and ask for hep, at least to know is it possible using ionic inside a existing project with only certain component?
Is it possible to dynamically import precompiled svelte components or whole svelte apps.
And when, how do I compile a single component in svelte 3. I found this approach, but nothing in the docs:
https://github.com/sveltejs/svelte/issues/1576
I want to combine several independent (hosted) Svelte apps on one page to one bigger svelte-app (microfrontend). The goal is, that every sub app can be independent deployed and hosted wherever (may be an own docker container). And any change should be visible in the aggregator app without recompiling it.
I think I wat to do something like this:
https://single-spa.js.org/docs/separating-applications.html
but with no other framework, that is blowing my app and components.
I don't want to use custom components, because of the inflexible styling of the Shadow DOM. I must be able to change css over a global stylesheet.
Has anyone an idea?
Thank you :)
You can take a look at Ara Framework. It has a standalone component named Nova Bridge.
This approach consists of a component that renders a placeholder micro-frontend view will be mounted. Then the component emits a DOM event named NovaMount that is listened by the JavaScript bundle of the micro-frontend to render it and mount it in run-time.
Here an example of the entry point for your micro-frontend.
import { mountComponent, load, loadById } from 'hypernova-svelte'
import Example from './components/Example.svelte'
const render = (name, { node, data }) => {
if (name === 'Example') {
return mountComponent(Example, node, data)
}
}
document.addEventListener('NovaMount', ({ detail }) => {
const { name, id } = detail
const payload = loadById(name, id)
if (payload) {
render(name, payload)
}
})
load('Example').forEach(render.bind(null, 'Example'))
The microfrontend uses hypernova-svelte. You can take a look in this article I wrote for implementing Svelte in Nuxt.
https://ara-framework.github.io/website/blog/2019/08/27/nuxt-js
Ive got a modular .NET application, which loads controllers, views and components from assemblies as plugins.
Going to learn React (totally new to it) - and got a question. Does React support splitting its components into multiple assemblies and loading them at runtime?
Yes, it does.
I suggest you to read React official documentation.
Almost every React component will produce some HTML markup for browser to show. The general idea of component splitting is to split HTML markup between several components like so
// App.js
class App extends React.Component {
render () {
return <div>
My first component
<Component1/>
</div>
}
}
// Component1.js
export default class Component1 extends React.Component {
render () {
return <div>
This is internals of component
</div>
}
}
I'm planning to build a very dynamic single page website template for Gatsby.
The theme will have many block-types componentes (30 or more) available, like:
Jumbotron
JumboTron2
JumbotronWithForm
MapWide
MapSquare
...
I intend to render the page based on an array of objects, each one having a type (like Jumbotron) to match a component and the necessary data to render it.
If I import all these componentes statically...
import Jumbotron from './../components/Jumbtron';
...they all will be included in the generated JS, which is bad because my JS will be too large.
If I use dynamic imports...
async componentDidMount(){
if(jumbotronTypeRequired){
this.jumbotron = await import('./../components/Jumbotron');
}
this.setState({ dynamicComponentsLoaded: true });
}
render(){
if(this.state.dynamicComponentsLoaded){
//render all
}
else{return (<div>Loading...</div>)}
}
...I can only fetch the component in a Promise, this means that the component will fully rendered after the ComponentDidMount, which is bad for SEO because my resulting HTML will not contain the fully rendered data.
Does Gatsby has a way to include only the necessary components to render the dynamic page while keeping a fully rendered HTML (not just render "Loading...")?
You can use the plugin gatsby-plugin-loadable-components-ssr to achieve this. There will however be a reference to the file path of each component in the bundle but at least the actual components do not get bundled.
I am trying to decide the best route to go for distributing a component that others can theme. They may need to change the html structure as well as the css/bootstrap styling. (I am using react-bootstrap with the component.
The only way I can see to do this is to make a component folder with all of the subcomponents in src/themes/default, src/themes/awesome, etc and then import them into the main component which people can then call by doing something like this...
This is just a concept, it probably isn't completely valid
import default from './themes/default/index.js`
import awesome from './themes/awesome/index.js`
const themes = {
default,
aweosme,
}
const MyComponent = ({ theme, otherprop }) => {
return (
<themes.default otherprop={otherprop} />
)
}
then if someone wanted to contribute a theme, they would have to write a whole component complete with html structure in the jsx and inline styles to go along with it. It would require them to be familiar with react, but I cannot see another way to do it unless I have missed something...
What do you think?