cannot GET /pageName when using React Navigation on web project - react-native

Browser page refreshes break my application.
I'm using react navigation in an expo universal application. When a user refreshed the browser on route "/", everything works as intended. When a user refreshed on any other route, e.g. "/search" I see this served:
Cannot GET /search
I have looked at deep linking
import * as Linking from 'expo-linking'
...
const prefix = Linking.createURL('/')
const linking={
prefixes: [prefix],
config: {
screens: PathsByName,
},
}
<NavigationContainer linking={linking}>
...
</NavigationContainer>
as well as a custom webpack
config.devServer.historyApiFallback = {
index: 'index.html'
}
but I still cant get simple page refreshes to load properly.

The problem was I customized the webpack config incorrectly.
This config works,
const createExpoWebpackConfigAsync = require('#expo/webpack-config')
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv)
// avoid improper settings here
return config
}

Related

Nuxt3 setup Apollo (or any plugin that uses .env)

I'm new to the node world and I'm having issues setting up my Nuxt3 project to use Apollo, but I think most of it is lack of knowledge with node and Nuxt.
Everything works fine when the setup code is in app.vue but I want it in a separate file to keep things tidy.
This is my latest attempt, I also tried using /server/api to return values, but I ran into top-level await issues.
I created a Stack Blitz instance to show what's happening. It renders successfully once, then shows an undefined error underneath. In my project, it's similar in a way where I see a flash of content, and then an empty white page and a console error that spaceId is undefined (braking the url).
plugins/apollo.ts
import { ApolloClient,createHttpLink,InMemoryCache} from '#apollo/client/core';
import { createApp, provide, h } from 'vue';
import { DefaultApolloClient,provideApolloClient} from '#vue/apollo-composable';
export default defineNuxtPlugin(async (nuxtApp) => {
const config = useRuntimeConfig();
const httpLink = createHttpLink({
uri: `https://someapi/${config.spaceID}/`,
headers: {
Authorization: `Bearer ${config.token}`,
},
});
// Cache implementation
const cache = new InMemoryCache();
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
provideApolloClient(apolloClient);
});
Thanks

How do I mock server-side API calls in a Nextjs app?

I'm trying to figure out how to mock calls to the auth0 authentication backend when testing a next js app with React Testing Library. I'm using auth0/nextjs-auth0 to handle authentication. My intention is to use MSW to provide mocks for all API calls.
I followed this example in the nextjs docs next.js/examples/with-msw to set up mocks for both client and server API calls. All API calls generated by the auth0/nextjs-auth0 package ( /api/auth/login , /api/auth/callback , /api/auth/logout and /api/auth/me) received mock responses.
A mock response for /api/auth/me is shown below
import { rest } from 'msw';
export const handlers = [
// /api/auth/me
rest.get(/.*\/api\/auth\/me$/, (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
user: { name: 'test', email: 'email#domain.com' },
}),
);
}),
];
The example setup works fine when I run the app in my browser. But when I run my test the mocks are not getting picked up.
An example test block looks like this
import React from 'react';
import {render , screen } from '#testing-library/react';
import Home from 'pages/index';
import App from 'pages/_app';
describe('Home', () => {
it('should render the loading screen', async () => {
render(<App Component={Home} />);
const loader = screen.getByTestId('loading-screen');
expect(loader).toBeInTheDocument();
});
});
I render the page inside the App component like this <App Component={Home} /> so that I will have access to the various contexts wrapping the pages.
I have spent about 2 days on this trying out various configurations and I still don't know what I might be doing wrong. Any and every help is appreciated.
This is probably resolved already for the author, but since I ran into the same issue and could not find useful documentation, this is how I solved it for end to end tests:
Overriding/configuring the API host.
The plan is to have the test runner start next.js as custom server and then having it respond to both the next.js, as API routes.
A requirements for this to work is to be able to specify the backend (host) the API is calling (via environment variables). Howerver, access to environment variables in Next.js is limited, I made this work using the publicRuntimeConfig setting in next.config.mjs. Within that file you can use runtime environment variables which then bind to the publicRuntimeConfig section of the configuration object.
/** #type {import('next').NextConfig} */
const nextConfig = {
(...)
publicRuntimeConfig: {
API_BASE_URL: process.env.API_BASE_URL,
API_BASE_PATH: process.env.API_BASE_PATH,
},
(...)
};
export default nextConfig;
Everywhere I reference the API, I use the publicRuntimeConfig to obtain these values, which gives me control over what exactly the (backend) is calling.
Allowing to control the hostname of the API at runtime allows me to change it to the local machines host and then intercept, and respond to the call with a fixture.
Configuring Playwright as the test runner.
My e2e test stack is based on Playwright, which has a playwright.config.ts file:
import type { PlaywrightTestConfig } from '#playwright/test';
const config: PlaywrightTestConfig = {
globalSetup: './playwright.setup.js',
testMatch: /.*\.e2e\.ts/,
};
export default config;
This calls another file playwright.setup.js which configures the actual tests and backend API mocks:
import {createServer} from 'http';
import {parse} from 'url';
import next from 'next';
import EndpointFixture from "./fixtures/endpoint.json";
// Config
const dev = process.env.NODE_ENV !== 'production';
const baseUrl = process?.env?.API_BASE_URL || 'localhost:3000';
// Context
const hostname = String(baseUrl.split(/:(?=\d)/)[0]).replace(/.+:\/\//, '');
const port = baseUrl.split(/:(?=\d)/)[1];
const app = next({dev, hostname, port});
const handle = app.getRequestHandler();
// Setup
export default async function playwrightSetup() {
const server = await createServer(async (request, response) => {
// Mock for a specific endpoint, responds with a fixture.
if(request.url.includes(`path/to/api/endpoint/${EndpointFixture[0].slug}`)) {
response.write(JSON.stringify(EndpointFixture[0]));
response.end();
return;
}
// Fallback for pai, notifies about missing mock.
else if(request.url.includes('path/to/api/')) {
console.log('(Backend) mock not implementeded', request.url);
return;
}
// Regular Next.js behaviour.
const parsedUrl = parse(request.url, true);
await handle(request, response, parsedUrl);
});
// Start listening on the configured port.
server.listen(port, (error) => {
console.error(error);
});
// Inject the hostname and port into the applications publicRuntimeConfig.
process.env.API_BASE_URL = `http://${hostname}:${port}`;
await app.prepare();
}
Using this kind of setup, the test runner should start a server which responds to both the routes defined by/in Next.js as well as the routes intentionally mocked (for the backend) allowing you to specify a fixture to respond with.
Final notes
Using the publicRuntimeConfig in combination with a custom Next.js servers allows you to have a relatively large amount of control about the calls that are being made on de backend, however, it does not necessarily intercept calls from the frontend, the existing frontend mocks might stil be necessary.

Next JS route is not resolving in production build

I have a following route pattern in the custom server of NextJs project. Everything works fine in the development. But in production build the route is not recognised and goes to 404 page.
Routes
{ name: 'business-with-key', pattern: '/:keyword-in-:location', page: 'packages/index' },
In the development I can get both the params with this code.
packages/index.tsx
export const getServerSideProps: any = async (ctx: NextPageContext) => {
const { query, req } = ctx;
const { keyword, location } = query;
But when I build the project in docker and run it, the route http://localhost:3000/photo-in-london reaches 404 when deep linked. Works fine with SPA navigation.
Any idea what I'm doing wrong here?

Expo deep linking in React Native Web

Trying to make deep linking for React Native Web work. Browsed many articles and finally found a solution proposed for the exact problem faced in this link whch doesn't work for me.
Expo documentation says use
const prefix = Linking.makeUrl('/')
and set the prefix in the AppNavigator.
Wondering how can I point to my react native web app when use clicks a link. The problem is Linking.makeUrl('/') returns exp://localhost:19006/ on my laptop. As browser wouldn't recognize exp as scheme is unable to open my URL.
I tried setting the scheme to https in app.json but still Linking.makeUrl('/') returns the scheme as expo.
In my app when user clicks on static html page which I load in the app I want to route back to my app. As I am unable to get right scheme for React Native Web using Expo unable to proceed further.
Thank you.
Attaching the code provided in the link.
import React from 'react'
import { createSwitchNavigator } from '#react-navigation/core'
import { createBrowserApp } from "#react-navigation/web"
import { Linking } from 'expo'
const prefix = Linking.makeUrl('/')
const AppNavigator = createBrowserApp(createSwitchNavigator({
Landing: {
screen: LandingScreen,
path: '/'
},
Login: {
screen: LoginScreen,
path: 'login'
}
}, {
initialRouteName: 'Landing',
backBehavior: 'history'
}))
export default () => <AppNavigator uriPrefix={prefix} />
Try :
const prefix = Linking.createURL('/');

nuxtServerInit in Modules mode does not run

I'm using nuxt.js in Universal mode and i'm trying to run nuxtServerInit() in one of my store actions, however it is not running.
In the docs it says...
If you are using the Modules mode of the Vuex store, only the primary
module (in store/index.js) will receive this action. You'll need to
chain your module actions from there.
However I don't quite understand what you need to do in order to make this work. Also if you need to use the primary module, then why would you need to use the module mode at all? Then you should just need to use the Classic mode.
store/posts.js
export const state = () => ({
loadedPosts:[]
});
export const getters = {
get(state){
return state
}
};
export const mutations = {
setPosts(state, payload){
state.loadedPosts = payload;
}
};
export const actions = {
async nuxtServerInit ({commit}){
const {data} = await axios.get('somedata')
console.log('I cannot see this comment');
commit('setPosts', data.results)
}
};
As it says in the documentation, you really need to have that function in the index.js file inside the store folder, which will not work otherwise.
here's an example of a production NuxtJs universal application with the ./store/index.js only with that file, you can easily call other stores methods by prefixing them with the file name, as the example shows auth/setAuth
I just faced the problem that nuxtServerInit was not called. The reason was in nuxt.config.js where ssr was set to false.
nuxt.config.js
export default {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
// ssr: false, <-- Remove or out comment the line
/*
** Nuxt target
** See https://nuxtjs.org/api/configuration-target
*/
target: 'server',
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
}
}