#fullcalendar/google-calendar breaks with 'gatsby build' - node.js

#fullcalendar/google-calendar seems to try to fetch JSON during the static gatsby build. I am unsure where to start looking.
When running gatsby build on my project the build breaks with the following error:
failed Building static HTML for pages - 3.026s
error Building static HTML failed for path "/calendar/"
6431 | body = encodeParams(params);
6432 | }
> 6433 | var xhr = new XMLHttpRequest();
| ^
6434 | xhr.open(method, url, true);
6435 | if (method !== 'GET') {
6436 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
WebpackError: ReferenceError: XMLHttpRequest is not defined
- main.js:6433
node_modules/#fullcalendar/common/main.js:6433:1
- main.js:54
node_modules/#fullcalendar/google-calendar/main.js:54:24
- main.js:6199
node_modules/#fullcalendar/common/main.js:6199:1
- main.js:6187
node_modules/#fullcalendar/common/main.js:6187:1
- main.js:6170
node_modules/#fullcalendar/common/main.js:6170:1
- main.js:6162
node_modules/#fullcalendar/common/main.js:6162:1
- main.js:6113
node_modules/#fullcalendar/common/main.js:6113:1
- main.js:6928
node_modules/#fullcalendar/common/main.js:6928:1
- main.js:7306
node_modules/#fullcalendar/common/main.js:7306:1
The page is defined as follows:
import React from "react"
import FullCalendar from '#fullcalendar/react'
import dayGridPlugin from '#fullcalendar/daygrid'
import googleCalendarPlugin from '#fullcalendar/google-calendar';
export default class DemoApp extends React.Component {
render() {
return (
<FullCalendar
plugins={[ dayGridPlugin, googleCalendarPlugin]}
initialView="dayGridMonth"
googleCalendarApiKey='XXX'
height="100vh"
eventSources= {[
{
googleCalendarId: 'en.indian#holiday#group.v.calendar.google.com',
color: '#1f78b4'
}
]}
/>
)
}
}
I am not sure how to create an executable test case, but am very happy to receive advice. Any pointers on how I can make this work would be highly appreciated.
Using #loadable works both for build and develop versions.
import React from "react"
import loadable from '#loadable/component'
const OtherComponent = loadable(() => import('../components/calendar.js'))
function MyComponent() {
return (
<OtherComponent />
)
}
export default function Home() {
return <MyComponent />
}

Try using the following snippet in your gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /#fullcalendar\/google-calendar/,
use: loaders.null(),
},
],
},
})
}
}
Some third-party dependencies use some global objects like window or document to make their stuff. This is perfectly valid when running gatsby develop since the code is compiled on the browser-side. However, gatsby build occurs in the server-side (your Node server) where obviously no window, because it's not even already defined yet.
That's why you need to add a null loader to the webpack's config by calling the onCreateWebpackConfig API, to avoid the dependency transpilation on the server-side.
The rule is a regular expression (that's why is between slashes) and literally, the test value matches a path in your node_modules folder to look for the dependency location, so, you must put there the exact folder name, I've assumed that is #fullcalendar/google-calendar but you have some potential folders that may create the conflict too:
import FullCalendar from '#fullcalendar/react'
import dayGridPlugin from '#fullcalendar/daygrid'
import timeGridPlugin from '#fullcalendar/timegrid'
import googleCalendarPlugin from '#fullcalendar/google-calendar';
Using #loadable/component:
import React from "react"
import loadable from '#loadable/component'
const OtherComponent = loadable(() => import('../components/calendar.js'))
function MyComponent() {
return (
<OtherComponent />
)
}
export default function Home() {
return <MyComponent />
}

Related

Error: Invalid `paths` value returned from getStaticPaths (without any changes on files) Slug

iam recently receiving this error message without any changes to files. I deleted some products and categories via the webGUI which might cause this?
Environment is:
Frontend: React, Next.js, TypeScript & Tailwind
Backend: Laravel
Error:
> Build error occurred
Error: Invalid `paths` value returned from getStaticPaths in /category/[slug].
`paths` must be an array of strings or objects of shape { params: [key: string]: string }
at buildStaticPaths (/var/www/domain/node_modules/next/dist/build/utils.js:490:15)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async /var/www/domain/node_modules/next/dist/build/utils.js:615:119
at async Span.traceAsyncFn (/var/www/domain/node_modules/next/dist/telemetry/trace/trace.js:60:20) {
type: 'Error'
}
Category Slug tsx content:
import Container from "#components/ui/container";
import { getLayout } from "#components/layout/layout";
import Subscription from "#components/common/subscription";
import CategoryBanner from "#containers/category-banner";
import { useRouter } from "next/router";
import CategoryProductsGrid from "#components/category/category-products-grid";
export { getStaticPaths, getStaticProps } from "#framework/ssr/category";
export default function Category() {
const { query } = useRouter();
return (
<div className="border-t-2 border-borderBottom">
<Container>
<CategoryBanner className="my-4"/>
<div className="pb-16 lg:pb-20">
<CategoryProductsGrid
classname="3xl:grid-cols-6"
categorySlug={query?.slug as string}
/>
</div>
<Subscription />
</Container>
</div>
);
}
Category.getLayout = getLayout;
SSR for category.ts:
// This function gets called at build time
export async function getStaticPaths({ locales }: GetStaticPathsContext) {
const categories = await fetchCategories({
queryKey: [API_ENDPOINTS.CATEGORIES, { limit: 100, parent: null }],
});
const paths = categories?.data?.flatMap((category: Category) =>
locales?.map((locale) => ({ params: { slug: category.slug }, locale }))
);
return {
paths,
fallback: "blocking",
};
}
Notes:
the only changes were made before the error occured via the webGUI (deleted products).
i deleted all locales on configured one locale. Maybe theres an issue. But after these changes the build ran fine for a week.
when i run the same code on my local computer with the same node etc. Versions it works. Is there any cache that must be deleted to make it work again?
Thank you in advance for any tip that could cause this. I tried alot of things but cant figure it out yet.

AWS-CDK: Need to pass resource generated in pipeline to a created stack

I'm currently working on a cross-account deployment pipeline.
I'm using 4 different stacks:
BackendPipelineStack
CommonInfrastructureStack
AssetDeploymentStack
BusinessAssetAPIStack
The last 2 stacks both have props that include a generated Layer and built JS files (for the different Lambdas).
My cdk.ts looks like this:
import * as cdk from "#aws-cdk/core"
import { BackendPipelineStack } from "../lib/backend-pipeline"
import { BusinessAssetAPIStack } from "../lib/business-asset-api-stack"
import { projectConfig } from "../config/config"
import { AssetDeploymentStack } from "../lib/asset-deployment-stack"
import { CommonInfrastructureStack } from "../lib/common-infrastructure-stack"
const app = new cdk.App()
const commonInfraStack = new CommonInfrastructureStack(app, "CommonInfrastructureStack", {
stackName: `${projectConfig.resourcePrefix}-common-infrastructure-stack`,
})
const apiStack = new BusinessAssetAPIStack(app, "BusinessAssetAPIStack", {
stackName: `${projectConfig.resourcePrefix}-business-asset-api-stack`,
...,
installationUserEmailIndexName: commonInfraStack.installationTechnicalAssetUserEmailIndexName,
})
const deploymentStack = new AssetDeploymentStack(app, "AssetDeploymentStack", {
stackName: `${projectConfig.resourcePrefix}-asset-deployment-stack`,
...,
installationAccountRegionIndexName: commonInfraStack.installationAccountRegionIndexName,
})
new BackendPipelineStack(app, "BackendPipelineStack", {
nonProdAccountId: "nonProdAccountId",
apiStack,
commonInfraStack,
deploymentStack,
})
My BackendPipelineStack stack is the one generating the codepipeline.Artifacts that store both the built JS files and Layers.
//backend-pipeline.ts
export class BackendPipelineStack extends Stack {
...
const lambdaBuildOutput = new Artifact("DistArtifact")
const lambdaLayer = new Artifact("LayerArtifact")
...
I want to be able to pass both Artifacts to the other stacks that are passed thru the PipelineStack constructor.
Is there anyway to do this?
I found the answer for those who would be stuck in the same situation as I was.
Looking into pipeline actions, there is one called CloudFormationCreateOrUpdateStack that allows to override parameters provided in the Lambda Stack thru CfnParametersCode (here's a python example).

How to share UI state in single-spa using RxJs?

As per the single-spa official doc, we can share the application's UI state by using RxJs.
Observables / Subjects (RxJs) - one microfrontend emits new values to
a stream that can be consumed by any other microfrontend. It exports
the observable to all microfrontends from its in-browser module, so
that others may import it.
Link: https://single-spa.js.org/docs/recommended-setup/#ui-state
Link: https://single-spa.js.org/docs/faq/#how-can-i-share-application-state-between-applications
I was trying to create an example in React, where I am using single-spa parcel to include my micro-apps in root application. I was trying to share the UI state using RxJs.
When I googled it for single-spa RxJs, I didn't find anything. Can anyone provide me a basic example where I will be able to share UI state for below use cases:
Sharing the UI state from root app to my micro-apps.
Sharing the UI state from micro-apps to root apps.
Sharing the UI state between micro-apps.
Here is a high level overview on how to approach this:
add rxjs as a shared dependency in your import map
"rxjs": 'https://unpkg.com/#esm-bundle/rxjs/system/rxjs.min.js,
"rxjs/operators": 'https://unpkg.com/#esm-bundle/rxjs/system/rxjs-operators.min.js,
consider pinning these to a specific version!
create a utility module (create-single-spa makes this easy!) that sets up and exports the observable with data that you need
include this utility module in importmap too
import and subscribe to observable from the utility module in the apps that need it
don't forget to unsubscribe when your apps unmount.
celebrate 🎉
I have created single-spa-example-rxjs-shared-state as an example repo that shows how to use an Rxjs utility module with cross-frontend imports.
This does the trick
In root html js file add the following
Import { Subject, Subscription } from 'https://dev.jspm.io/rxjs#6/_esm2015';
import { filter, map } from 'https://dev.jspm.io/rxjs#6/_esm2015/operators';
export class EventBusService {
constructor() {this.subject$ = new Subject(); }
emit(event) {
this.subject$.next(event);
}
on(eventName, action) {
return this.subject$.pipe(
filter( (e) => e.name === eventName),
map( (e) => e["data"])).subscribe(action);
}
}
var EventBus= new EventBusService()`enter code here`;
System.import('single-spa').then(function (singleSpa) {
singleSpa.registerApplication(
'app1',
function () {
return System.import('app1');
},
function (location) {
return true;
// return location.pathname.startsWith('/app1');
},
{ EventBus: EventBus }
);
singleSpa.registerApplication(
'app2',
function () {
return System.import('app2');
},
function (location) {
return true
// return location.pathname.startsWith('/app2');
},
{ EventBus: EventBus }
)
singleSpa.start();
})
In component
import { Component,OnInit ,ChangeDetectorRef} from '#angular/core';
import { assetUrl } from 'src/single-spa/asset-url';
import { singleSpaPropsSubject, SingleSpaProps } from 'src/single-spa/single-spa-props';
import { Subscription } from 'rxjs';
#Component({
selector: 'app1-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
singleSpaProps: SingleSpaProps;
subscription: Subscription;
title = 'app1';
yoshiUrl = assetUrl("yoshi.png");
msgFromMicro="";
titleToPass="";
constructor(private ChangeDetectorRef:ChangeDetectorRef){
}
ngOnInit(): void {
this.subscription = singleSpaPropsSubject.subscribe(
props => {
this.singleSpaProps = props;
console.log(props);
this.lookForEvents();
}
);
}
lookForEvents(){
this.singleSpaProps['EventBus'].on('msgFrmMicro2',(data)=>{
this.msgFromMicro=data;
this.ChangeDetectorRef.detectChanges();
});
}
sendMsg(){
// alert(this.titleToPass);
debugger;
this.singleSpaProps['EventBus'].emit({name:'msgFrmMicro1',data:this.titleToPass});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Take look at the following repo, handled the same scenario by passing observable ref to micro apps through customprops of single spa
https://github.com/SENTHILnew/micro_spa_intercom

How to use node/npm package (oxford-dictionary) in react native?

I am trying to use npm oxford-dictionary package in react-native, I installed
"npm install oxford-dictioary" and run this file as "node app.js" on a terminal and works fine, However, when I tried to use in react native it doesn't work, can anyone help me what's is the problem. Is it possible to use this api at all with just react-native or I would have to build backend with nodejs ?
app.js
var Dictionary = require("oxford-dictionary");
var config = {
app_id : "-------",
app_key : "--------",
source_lang : "en"
};
var dict = new Dictionary(config);
var props = {
word: "stupendous",
};
var oxfordApi = {
getRovers(){
var lookup = dict.synonyms(props);
return fetch(lookup).then((res) => res.json());
}
}
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
//import oxfordApi from './oxfordApi';
import globals from 'node-libs-react-native/globals';
var Dictionary = require("oxford-dictionary");
var config = {
app_id : "-------",
app_key : "--------------------------",
source_lang : "en"
};
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
rovers: []
}
}
componentWillMount() {
var dict = new Dictionary(config);
var lookup = dict.find("awesome");
lookup.then((res) => {
this.setState({
rovers: res.rovers
})
});
}
render() {
console.log("Rovers: ", this.state.rovers);
return (
<View style={styles.container}>
<Text>Hello wordl</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
The result When I run "run npm ios"
The package at "node_modules/oxford-dictionary/index.js" attempted to import the Node standard library module "https". It failed because React Native does not include the Node standard library. Read more at https://docs.expo.io/versions/latest/introduction/faq.html#can-i-use-nodejs-packages-with-expo
Unfortunately as you have quite rightly identified you cannot use that npm package with react-native as it does not have the https module.
However, looking at the package oxford-dictionary it is a single file that provides a few helper methods to construct specific network requests to the Oxford Dictionary api.
It wouldn't be too difficult to re-write these in terms of fetch and make your own helper file. You could even create your own react-native package for the Oxford Dictionary api and publish it to npm.
With regard to accessing the Oxford Dictionary's api, there shouldn't be an issue doing it as it is just network requests. fetch should be able to cope with it. You just won't be able to use the oxford-dictionary npm package to make the requests.
I re-wrote the package, methods and published it to the npm. react-native-oxford-dictionary

How to configure Prism with Nuxt

How can I configure Prism to work with Nuxt? I added it as a vendor in the nuxt.config.js file:
// * Build configuration
build: {
// * You can extend webpack config here
vendor: ['axios', 'prismjs'],
extend(config, ctx) {
if (ctx.isServer) {
config.externals = [
nodeExternals({
whitelist: [/^vuetify/]
})
];
}
}
}
Then in my page in the script section I import it:
<script>
import Prism from'prismjs';
export default {
data() {
return {
post: {}
};
},
// more data...
How can I use it then? I've tried calling it in mounted but it doesn't work. No errors are returned but it doesn't change anything on site.
mounted() {
Prism.highlightAll();
}
Turned out to be working, just forgot about including css styles.

Resources