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.
Related
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.
In my NextJS app, I have node_modules (js files) for themes for certain elements on the page. I want to load only the files I need this based on this.props.theme for the component. How/where would I do this in my component. Basically, if I have a bunch of files for themes:
theme-red.js
theme-orange.js
theme-yellow.js
theme-green.js
theme-blue.js
theme-purple.js
theme-violet.js
theme-pink.js
theme-rainbow.js
In the props, I would this.props.themepassed in and then load in require(theme-${this.props.theme}.js)
You can use the import function:
const theme = await import(./{path-to-the-files}/theme-${this.props.theme}.js)
It would be good to include this in the componentWillMount function of the component.
https://nextjs.org/docs/advanced-features/dynamic-import
https://javascript.info/modules-dynamic-imports
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
I've created a component inside my layouts folder, and have tried to use a query to grab information from contentful. My code is pretty identical to that which I have used inside another working component, inside the pages folder. However, that in the layouts folder isn't working; this.props.data console logs as undefined.
Is there some special way to query when it comes to components in the layouts folder? Is there something I'm missing here? I've read both that I can and cannot query inside the layouts folder in GatsbyJS...
here is the code for my component inside the layouts folder:
import React, { Component } from 'react'
export default class Header extends Component {
render() {
return (
my component code
}
export const headerQuery = graphql`
query headerQuery {
allContentfulBlogPost {
edges {
node {
postTitle
postDate
}
}
totalCount
}
}
`
The answer was covered in the comments.
No.
Data is delivered to components in Gatsby only via queries in pages or layouts. This single point of entry allows Gatsby to compile your data to static JSON files on disk, and to pre-fetch data, etc.
My Ember.js has many components that the end-user can use to compose a page. How can I display a dynamic list of the components that exist in my Ember Application?
I imagine the registered components is somewhere in the Ember.Application object, but I'm having a hard time finding something I can use.
# in the route
import computed from 'ember-computed';
import getOwner from 'ember-owner/get';
...
{
components: computed(function () {
return getOwner(this).lookup('container-debug-adapter:main')
.catalogEntriesByType('component')
.filter(componentName => componentName.includes('composables'))
})
}