next build with mdx files - next.js

I am building a blog. During development I am able to go into a directory and pull in all of my articles like this.
import fs from "fs";
import matter from "gray-matter";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import rehypeHighlight from "rehype-highlight";
import { serialize } from 'next-mdx-remote/serialize'
import Remote from "./remote";
import 'katex/dist/katex.min.css';
import langJavascript from "highlight.js/lib/languages/javascript";
import langTypescript from "highlight.js/lib/languages/typescript";
import langPython from "highlight.js/lib/languages/python";
import 'highlight.js/styles/a11y-dark.css'
const languages = {
javascript: langJavascript,
typescript: langTypescript,
python: langPython
}
async function getData(slug: string) {
const folder = "app/articles/";
const fileContent = fs.readFileSync(`${folder}${slug}.mdx`, "utf-8");
const { data, content } = matter(fileContent);
const source = await serialize(content, { mdxOptions: { remarkPlugins: [remarkGfm, remarkMath], rehypePlugins: [rehypeKatex,
[rehypeHighlight, { languages, ignoreMissing: true }]] } })
return { data, source };
}
export default async function Markdown({ slug }: { slug: string }) {
const { data, source } = await getData(slug)
return <Remote className="prose" source={source}></Remote>
}
it works perfectly in development.
however after deploying I get 404 errors because it seems that the build is not keeping the mdx files.
I am deploying on vercel.
I understand this has to do with the path not being there after the build, but I am unsure on what will fix it.
I am using next.js 13 with the expiremental appdir
view in development with path view in development
view in prod view in production

Related

NextJS 13 - Loading / App Structure Design Issue

Summary : The structure is waiting for query to fully load before loading the page, it works almost like a PHP app where server render has to complete before the page is shown.
I'm trying to get it to at least load the website first , then query and load the server data. Let me provide more information below.
Hosted on Vercel. NextJS 13 App is currently on Beta.
I feel that i structured it wrongly causing the app to run like a server side rendering site. Could you please advise on structures for NextJS 13 App folder.
Route Structure
Route (app) Size First Load JS
┌ ○ / 0 B 0 B
├ λ /questions/[questionId] 144 B 66.8 kB
└ ○ /search
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
○ (Static) automatically rendered as static HTML (uses no initial props)
From my understanding, NextJS 13 App , by default all are treated as ServerSide pages instead of Client unless you declare the client.
When the Link is clicked routed towards /questions , it will take 2.35 seconds before the UI will update , the 2.35 seconds was a fetch query "fetchQuestions" under the Question File (Code below)
Root File Summary
import Link from 'next/link';
import { Suspense } from 'react';
import { qLists } from '../typings';
import { SideBarRight } from './SideBarRight';
import { SideBarLeft } from './SideBarLeft';
const fetchqList = async () => {
const res = await fetch('https://example.com', {
next: { revalidate: 5 },
});
const data = await res.json();
const qLists: qLists[] = data;
return qLists;
};
async function Home() {
const qLists = await fetchqList();
{qLists.map((qList) => (
<Link href={`/questions/${qList.id}`}>
XXX
</Link>
))}
<SideBars />
return (xxx);
}
export default Home;
Question File Summary
import Link from 'next/link';
import { Suspense } from 'react';
import { SideBarLeft } from '../../SideBarLeft';
import SideBarRight from '../../SideBarRight';
type PageProps = {
params: {
questionId: string;
};
};
const fetchQuestions = async (questionId: string) => {
const res = await fetch(`https://exmaple.com/${questionId}`);
const questions = await res.json();
return questions;
};
async function questionPage({ params: { questionId } }: PageProps) {
const question = await fetchQuestions(questionId);
return (
<SideBarLeft />
<Suspense fallback={<p>Loading feed...</p>}>
{question.items[0].value}
</Suspense>
);
}
export default questionPage;

Using the context API in Next.js

I'm building a simple Next.js website that consumes the spacex graphql API, using apollo as a client. I'm trying to make an api call, save the returned data to state and then set that state as context.
Before I save the data to state however, I wanted to check that my context provider was actually providing context to the app, so I simply passed the string 'test' as context.
However, up[on trying to extract this context in antoher component, I got the following error:
Error: The default export is not a React Component in page: "/"
My project is set up as follows, and I'm thinking I may have put the context file in the wrong place:
pages
-api
-items
-_app.js
-index.js
public
styles
next.config.js
spacexContext.js
Here's the rest of my app:
spaceContext.js
import { useState,useEffect,createContext } from 'react'
import { ApolloClient, InMemoryCache, gql } from "#apollo/client"
export const LaunchContext = createContext()
export const getStaticProps = async () => {
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache()
})
const { data } = await client.query({
query: gql`
query GetLaunches {
launchesPast(limit: 10) {
id
mission_name
launch_date_local
launch_site {
site_name_long
}
links {
article_link
video_link
mission_patch
}
rocket {
rocket_name
}
}
}
`
});
return {
props: {
launches: data.launchesPast
}
}
}
const LaunchContextProvider = (props) => {
return(
<LaunchContext.Provider value = 'test'>
{props.children}
</LaunchContext.Provider>
)
}
export default LaunchContextProvider
_app.js
import LaunchContextProvider from '../spacexContext'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return (
<LaunchContextProvider>
<Component {...pageProps} />
</LaunchContextProvider>
)
}
export default MyApp
Any suggestions on why this error is appearing and how to fix it?

Handle 401 error in react-redux app using apisauce

The problem: i have many sagas that do not handle an 401 error in response status, and now i have to deal with it. I have apiservice based on apisause and i can write an response monitor with it to handle 401 error (like interceptors in axios). But i cant dispatch any action to store to reset user data, for example, because there is no store context in apiservice. How to use dispatch function in apiservice layer? Or use put() function in every saga when i recieve 401 response status is the only right way?
you can use refs for using navigation in 'apisauce' interceptors
this is my code and it works for me ;)
-- packages versions
#react-navigation/native: ^6.0.6
#react-navigation/native-stack: ^6.2.5
apisauce: ^2.1.1
react: 17.0.2
react-native: ^0.66.3
I have a main file for create apisauce
// file _api.js :
export const baseURL = 'APP_BASE_URL';
import { create } from 'apisauce'
import { setAPIInterceptors } from './interceptors';
const APIClient = create({ baseURL: baseURL })
setAPIInterceptors(APIClient)
and is file interceptors.js I'm watching on responses and manage them:
// file interceptors.js
import { logout } from "../redux/actions";
import { store } from '../redux/store';
import AsyncStorage from '#react-native-async-storage/async-storage';
export const setAPIInterceptors = (APIClient) => {
APIClient.addMonitor(monitor => {
// ...
// error Unauthorized
if(monitor.status === 401) {
store.dispatch(logout())
AsyncStorage.clear().then((res) => {
RootNavigation.navigate('login');
})
}
})
}
then I create another file and named to 'RootNavigation.js' and create a ref from react-native-navigation:
// file RootNavigation.js
import { createNavigationContainerRef } from '#react-navigation/native';
export const navigationRef = createNavigationContainerRef()
export function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.replace(name, params);
}
}
// add other navigation functions that you need and export them
then you should to set some changes in you App.js file:
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
finally in anywhere you can call this function for use react native navigations
full focument is in here that explain how to Navigating without the navigation prop
Navigating without the navigation prop

Quasar v2 Vue-Apollo Setup

I've recent switched over to Quasar v2 and I'm having trouble getting the info I need for the vue apollo setup. I am using https://apollo.vuejs.org/guide/installation.html#_1-apollo-client to try and install vue apollo into the framework using the boot file.
This is my boot/apollo.ts file
import { boot } from 'quasar/wrappers';
import ApolloClient from 'apollo-boost';
import VueApollo from 'vue-apollo';
const apollo = new ApolloClient({
uri: 'https://api.graphcms.com/simple/v1/awesomeTalksClone',
});
const apolloProvider = new VueApollo({
defaultClient: apollo,
});
export default boot(({ app }) => {
// for use inside Vue files (Options API) through this.$apollo
app.config.globalProperties.$apollo = apollo;
// ^ ^ ^ this will allow you to use this.$apollo (for Vue Options API form)
// so you won't necessarily have to import apollo in each vue file
});
export { apollo, VueApollo, apolloProvider };
And this is where I am trying to use it:
import { Vue } from 'vue-class-component';
export default class LoginPage extends Vue {
public login() {
console.log(this.$apollo);
}
}
The error I'm getting is
Property '$apollo' does not exist on type 'LoginPage'.
I can see in the comment for the globalProperties it mentions the vue options api. Not sure if this is happening because I use vue-class-component.
I ended up added this below the export
declare module '#vue/runtime-core' {
interface ComponentCustomProperties {
$apollo: FunctionConstructor;
}
}

How to do Routing with redux-saga in Next.js app

I'm trying to migrate my react app to next.js app.
I like redux-saga
I like routing in redux-saga logic
And I want to do routing in redux-saga logic as I used to do!
but I cannot figure out how to do this.
question is..
How to route with redux-saga logic in Next.js?
Is this bad practice doing this? I think putting routing logic on saga seems more reasonable. But I think it is not a popular way. Why it is not used by many people?
To help understanding my situations.
I usally do routing in react app like below
one of my saga logic as example
export function* deletePost(action) {
const { postId } = action;
//delete post
yield api.postApi.deletePost(postId);
//route page to home ("/")
yield put(actions.router.push("/"));
}
I used 'connected-react-router' to do this.
and actions.router is exported from below file.
import { routerActions as router } from "connected-react-router"
export { router }
And below is how I configured my redux store
import { applyMiddleware, compose, createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import { routerMiddleware } from "connected-react-router";
import { createBrowserHistory } from "history";
import { composeWithDevTools } from "redux-devtools-extension";
import { createRootReducer } from "data/rootReducer";
import rootSaga from "data/rootSaga";
const history = createBrowserHistory();
const sagaMiddleware = createSagaMiddleware();
const rootReducer = createRootReducer(history);
const env = process.env.NODE_ENV;
let composeFn = composeWithDevTools;
if (env === "production") {
composeFn = compose;
}
export default function configureStore() {
const store = createStore(
rootReducer,
composeFn(applyMiddleware( sagaMiddleware, routerMiddleware(history)))
);
sagaMiddleware.run(rootSaga);
return { history, store };
}

Resources