Meteor setup (boilerplate) with server-render and react-router? - javascript

I've only been developing with Meteor 1.4 for a while, and now made the jump to 1.6. Things sure have changed (for the worse).
Meteor used to be so easy to get started with. Now everything is a jumbled mess. It seems like every package wants to insert itself right at the start, so that you can't just import it and use it anymore, you have to change the setup/boilerplate of your app to get it to work. That also means the official documentation is useless because it can't account for every package you want to use.
Anyway, I want to get started with react-router and server-render, which also requires react-helmet (I think). All of these are new to me and hey, they want to insert themselves right away and they all have awful documentation to begin with.
Here's what I have so far, based on googling:
lib/main.js:
import React from 'react'
import { Helmet } from 'react-helmet'
import App from '../imports/ui/App.js'
if (Meteor.isClient) {
import { hydrate } from 'react-dom'
hydrate(<App />, document.getElementById('app'))
}
else {
import { renderToString } from 'react-dom/server'
import { onPageLoad } from 'meteor/server-render'
import NodeCache from 'node-cache'
const renderCache = new NodeCache({stdTTL: 432000})
onPageLoad((sink) => {
const path = sink.request.url.path
let htmlString = renderCache.get(path)
if (!htmlString) {
htmlString = renderToString(<App location={path} />)
const helmet = Helmet.renderStatic()
renderCache.set(path, htmlString)
renderCache.set(path + "_title", helmet.title.toString())
renderCache.set(path + "_meta", helmet.meta.toString())
renderCache.set(path + "_link", helmet.link.toString())
}
sink.appendToHead(renderCache.get(path + "_title"))
sink.appendToHead(renderCache.get(path + "_meta"))
sink.appendToHead(renderCache.get(path + "_link"))
sink.renderIntoElementById("app", htmlString);
})
}
And then App.js is just an empty component right now.
I don't know where to put my routing, or how (the docs assume you already know, for some reason). I think it also needs to insert itself in the hydrate() method on the client, but the example I got it from did not do that so I don't really know.
I don't know whether to put my main.html on the client or both client and server.
I don't know how to set titles and meta tags and whatnot for each route. (I thought this would actually be in the documentation for react-helmet since that's all it's supposed to do but no...)
Can anyone help me with the rest of this boilerplate? I have no idea what's going on in the Meteor world anymore.

Related

Why is dynamic importing of dayjs not working in typescript?

I am working on a web screen inside a .NET app and I am trying to send date time preference from the system to the web screen using CefSharp settings and setting
AcceptLanguageList = CultureInfo.CurrentUICulture.Name
In my typescript code I want to use dayjs and import dynamically 'dayjs/locale/${language}' where language comes from AcceptLanguageList above.
import React, { useState } from 'react';
import dayjs, { Dayjs } from 'dayjs';
import localeData from 'dayjs/plugin/localeData';
dayjs.extend(localeData);
var lang = navigator.languages != null ? navigator.languages[0] : navigator.language;
lang = lang.toLowerCase();
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
});
The thing is, when I run this code in browser and try to import 'dayjs/locale/fr-ca', for example, it works fine, but when 'fr-ca' comes from CefSharp, then the import fails with
Uncaught (in promise) TypeError: Failed to resolve module specifier
'dayjs/locale/fr-ca'
Any help is much appreciated.
If you want to use a dynamic path for the dynamic import then you'll first have to list all of the possible paths that you will potentially want to have, otherwise your bundler wont know which files to include.
You can add import('dayjs/locale/fr-ca') anywhere in your code and the bundler will include it when it builds your app for the browser.
And you'll still going to get that error if you don't have a locale for user's language, so you should catch that case:
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
},
() => { // in case the import fails
// maybe default to english
dayjs.locale('en');
setAdapterLocale('en');
});
I figured it out. The problem was that when building the package for the .net app, the package was created using rollup (which is not the case when running in browser).
Rollup needs some special config to support dynamic import:
https://www.npmjs.com/package/#rollup/plugin-dynamic-import-vars

What is the React Sigma style file mentioned in their setup documentation?

This is my first time making graphs in React so I'm following the guide and documentation. I have no prior experience with graphology, sigma.js or react-sigma (I know how to use normal React).
The setup documentation says:
Import the React Sigma style file in your application. Example : import "#react-sigma/core/lib/react-sigma.min.css"
What are style files? CSS? How can I make one? I can't find any documentation. Is it something basic from a previous library?
Honestly I'm finding it very hard to learn sigma.js and insert it in my react website. I can't find any guides. Are there any? I just want to start with a simple graph and learn from there.
The documentation refers specifically to their own CSS file which must be imported in a React app like they are showing in the example:
import "#react-sigma/core/lib/react-sigma.min.css";
Disclaimer: depending on your React app setup, the way to import a CSS file might differ.
The example in the documentation was broken when I wrote this answer. I opened an issue on the react-sigma repo and it was fixed since then.
When I tried it, some dependencies were missing and some changes were needed.
npm install #react-sigma/core sigma graphology graphology-types lodash
import { useEffect } from "react";
import Graph from "graphology";
import { SigmaContainer, useLoadGraph } from "#react-sigma/core";
// Import the style file here
import "#react-sigma/core/lib/react-sigma.min.css";
export const LoadGraph = () => {
// first change to their example
const loadGraph = useLoadGraph();
// also wrapped their graph instantiation side-effect with useEffect
useEffect(() => {
const graph = new Graph();
graph.addNode("first", {
// Required position
x: 1,
y: 1,
size: 15,
label: "My first node",
color: "#FA4F40"
});
// Calling the function that was missing from the example
loadGraph(graph);
}, [loadGraph]);
// Returning null to get a valid component
return null;
};
export const DisplayGraph = () => {
return (
<SigmaContainer style={{ height: "500px", width: "500px" }}>
<LoadGraph />
</SigmaContainer>
);
};
Note that I used TypeScript for the example, which gives insightful error messages since react-sigma provides its own types.
Then it was clear that the useLoadGraph hook wasn't used properly since it doesn't accept any parameter and it returns a function accepting a graph parameter. This can be confirmed with the API documentation.
I also figured that lodash was missing from errors in the developer console.
Please refer to the documentation as it's now up-to-date.

Next.js: How to dynamically import external client-side only React components into Server-Side-Rendering apps developed?

I know this question has been asked multiple times before but none of the solution seems to work.
I'm trying to use the library 'react-chat-popup' which only renders on client side in a SSR app.(built using next.js framework) The normal way to use this library is to call import {Chat} from 'react-chat-popup' and then render it directly as <Chat/>.
The solution I have found for SSR apps is to check if typedef of window !=== 'undefined' in the componentDidMount method before dynamically importing the library as importing the library normally alone would already cause the window is not defined error. So I found the link https://github.com/zeit/next.js/issues/2940 which suggested the following:
Chat = dynamic(import('react-chat-popup').then(m => {
const {Foo} = m;
Foo.__webpackChunkName = m.__webpackChunkName;
return Foo;
}));
However, my foo object becomes null when I do this. When I print out the m object in the callback, i get {"__webpackChunkName":"react_chat_popup_6445a148970fe64a2d707d15c41abb03"} How do I properly import the library and start using the <Chat/> element in this case?
Next js now has its own way of doing dynamic imports with no SSR.
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
Here is the link of their docs: next js
I've managed to resolve this by first declaring a variable at the top:
let Chat = ''
then doing the import this way in componentDidMount:
async componentDidMount(){
let result = await import('react-chat-popup')
Chat = result.Chat
this.setState({
appIsMounted: true
})
}
and finally render it like this:
<NoSSR>
{this.state.appIsMounted? <Chat/> : null}
</NoSSR>
You may not always want to include a module on server-side. For
example, when the module includes a library that only works in the
browser.
Import the library normally in child component and import that component dynamically on parent component.
https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
This approach worked for me.

ApolloClient is not a constructor react-apollo

I am following this tutorial and trying to implement graphQl. There is an issue with the following line:
const client = new ApolloClient();
Strangely I cannot find anything in the react-apollo GitHub page for this. Is there something stupid that I am doing wrong.
import React, { Component } from 'react';
import ChannelsList from './ChannelsList.js';
import './App.css';
import {
ApolloClient,
gpl,
graphql,
ApolloProvider
} from 'react-apollo';
//issue with this line
const client = new ApolloClient();
const channelsListQuery = `
query ChannelsListQuery {
channels {
id,
name
}
}
`;
const ChannelsListWithData = graphql(channelsListQuery)(ChannelsList);
class App extends Component {
render() {
return (
<ApolloProvider client={client}>
<ChannelsListWithData />
</ApolloProvider>
);
}
}
export default App;
To provide a straightforward answer - ApolloClient is no longer a part of the react-apollo package, but made it to a package of it's own: apollo-client.
You may also see it being imported from apollo-boost, a convenience which "includes some packages that we [Apollo's authors] think are essential to developing with Apollo Client."
having the same issue here and actually following the same article (https://dev-blog.apollodata.com/full-stack-react-graphql-tutorial-582ac8d24e3b) as the OP. The issue is that the article is really old and out of date and I would not recommend using it as a guide (take a look at the comments in the article).
For a start I'd recommend looking at the docs. This link (http://graphql.org/graphql-js/) in particular is a good starting place for getting something up and running.

react JS how to make theme-able component

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?

Categories