Hey guys I am having a small issue, I have been building a test add for the following platforms [ Web, Phones, Desktop ]
The following frameworks I am using,
Expo
React Native
React Native Navigation
My issue is when on the PWA build after building the app, I am having an issue where if a user wants to directly navigate to a specific path OR refreshes the page the website returns 404 when clearly works in the following example GIF's below.
-- Expo dev tool: https://gyazo.com/0abc4161810cb14e74543b3dcb854b49
-- After running expo build:web
then after expo finished building the PWA I run npx serve web-build
: https://gyazo.com/ed699dcc4b13830647552b07ee112c62
I am not sure what added config I need to do or what? I have been searching my issue and cannot find anything
If anyone can help would be you guys !!
ADDED NOTE >>>
I haven't coded a login system or any type of cashing etc this is just components with one page having a button that sends a user to a page(Profile)
App.js
import LoginScreen from './views/login'
import ProfileScreen from './views/profile'
export default function App() {
return React.createElement(
(Platform.OS == 'web') ? web_navigator : mobile_navigator
);
}
function mobile_navigator() {
const Tab = createBottomTabNavigator();
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarStyle: {
backgroundColor: "#242629",
borderTopWidth: 0
},
tabBarOptions: {
showLabel: false,
}
}}
>
<Tab.Screen name="Login" component={LoginScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
function web_navigator() {
const Stack = createStackNavigator();
return (
<NavigationContainer linking={{
config: {
screens: {
Login: "/",
Profile: "/Profile/:Username?"
}
},
}}>
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Login.js
const Login = ({navigation}) => {
const [userName, setUserName] = useState('');
const [userPassword, setUserPassword] = useState('');
return (
<View style={styles.Body} >
{Platform.OS === 'web' ?
<View style={styles.Body_left} >
<Image
source={require("../assets/LeftPanel3.png")}
style={styles.Body_left_Picture}
/>
</View>
: null}
<SafeAreaView style={styles.Body_right} >
<View style={styles.Body_Container} >
<Image
source={require("../assets/PlaceHolderLogo.png")}
style={styles.Logo}
/>
<Text h1 style={styles.Login_Title}>Let's Sign In</Text>
<Text style={styles.Login_Title_Child}>Welcome Back!</Text>
<View style={styles.Input_Group} >
<TextInput value={userName} placeholder={'Enter Username'} placeholderTextColor="#fff" onChangeText={(inputOne) => setUserName(inputOne)} style={styles.Input} />
<TextInput value={userPassword} placeholder={'Enter Password'} placeholderTextColor="#fff" onChangeText={(inputTwo) => setUserPassword(inputTwo)} style={styles.Input} />
<Pressable style={styles.Btn_Main} onPress={() => navigation.navigate("Profile", {Username: userName})}>
<Text style={styles.Btn_Text}>Sign In</Text>
</Pressable>
</View>
</View>
</SafeAreaView >
</View>
);
}
export default Login;
Profile.js
export default function App({route}) {
const Profile_Username = route.params ? route.params.Username : "UnKnown"
const Profile_Picture = "https://www.trickscity.com/wp-content/uploads/2019/02/pubg-dp.jpeg"
return (
<View style={{ position: 'relative', backgroundColor: "#242629", flex: 1 }} >
<View style={{ position: 'relative', backgroundColor: "#242629", flex: 0.3 }} ></View>
<View style={{ position: 'relative', backgroundColor: "#16161a", flex: 1 }} >
<View style={styles.ProfileParent} >
<View style={styles.ProfilePictureParent}>
<Image
source={{uri: Profile_Picture}}
style={styles.ProfilePicture}
/>
</View>
<View style={styles.ProfileTitleBox}>
<Text style={styles.ProfileName}>{Profile_Username}</Text>
<Text style={styles.ProfileTag}>Member</Text>
</View>
</View>
</View>
</View>
);
}
---[ PWA Files ]---
serve.json
{
"headers": [
{
"source": "static/**/*.js",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}
manifest.json
{
"background_color": "#ffffff",
"display": "standalone",
"lang": "en",
"name": "DevBuild",
"short_name": "DevBuild",
"start_url": "/?utm_source=web_app_manifest",
"orientation": "portrait",
"icons": [
{
"src": "\\pwa\\chrome-icon\\chrome-icon-144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "\\pwa\\chrome-icon\\chrome-icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "\\pwa\\chrome-icon\\chrome-icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
CodePudding user response:
Solution
Thanks to @pfndesign
Told me to edit the serve.json to include
"rewrites": [
{ "source": "/**", "destination": "/index.html"}
]
Note I am not 100% sure on what it does but it worked for me,
pfndesign also linked me to this: https://github.com/vercel/serve-handler#options
Hope this helps anyone reading this :D
CodePudding user response:
your problem is not the expo or react-native, you need to use htaccess in your host to send all of your requests to index.html where your PWA is . the first time you are navigating to your PWA it will load the index.html and each route is loaded within that HTML file with the URL address bar changing according to your linking config but when you refresh the page host think that it has to go to subfolders because it has no idea that your routes don't exist outside of your PWA
simply create a .htaccess file inside of your PWA folder and add this code to it, it should solve your problem
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html [L]
</IfModule>
for your local environment edit serve.json and add code bellow
"rewrites": [
{ "source": "/**", "destination": "/index.html" }
]
for more info about rewrites, you can check https://github.com/vercel/serve-handler#options