I have an issue that I can't resolve. I'm working with node.js and I simply want to use an export router function in another file .
Here is the code from the import file:
import express from "express";
import * as zoneInstance from "../../controllers/objectInstance/zoneInstance.js";
import { mobilityRouter } from "../../controllers/routerFunction/routerLogic.js";
const router = express.Router();
/* Router for mobility render
// const mobilityRouter = (zone, instance) => {
// return (
// router.get("/mobility/" + zone, instance)
// );
// } */
mobilityRouter(zoneInstance.shoulder.zone, zoneInstance.shoulder.mobilityRender());
Here is the code from the export file:
import express from "express";
const router = express.Router();
// Router for mobility render
export const mobilityRouter = (zone, instance) => {
return (
router.get("/mobility/" + zone, instance)
);
}
// Router for reinforcement render
export const reinforcementRouter = (zone, instance) => {
return (
router.get("/reinforcement/" + zone, instance)
);
}
// Router for proprioception
export const proprioceptionRouter = (zone, instance) => {
return (
router.get("/proprioception/" + zone, instance)
);
}
In the index.js
// Routes for
import mobilityRouter from "./routes/mobility/mobilityAPI.js";
const app = express();
//for mobility URL
app.use("/", mobilityRouter);
When I copy past the 'mobilityRouter' function and use it in the import file it works perfectly, but once I put it in another file and exports it I have a "cannot GET/" in my browser. Thank you for your help.
You have different instances of router in both files. Either pass router as a parameter to the function in the other file or export & import in your routerLogic.js.
Related
I am using the following Component with Meteor
https://github.com/CaptainN/npdev-react-loadable
import { Loadable } from 'meteor/npdev:react-loadable';
I create my Loadable component as follows
const HomePageBlog = Loadable({
loading: () => <FullPageLoader />,
loader: () => import('./HomePageBlog'),
});
I have gone through the SSR setup in the docs and it looks something like this
Server index.js
import React from 'react';
import { renderToString, renderToNodeStream } from 'react-dom/server';
import { onPageLoad } from 'meteor/server-render';
import { StaticRouter } from 'react-router';
import { Helmet } from 'react-helmet';
import Loadable from 'react-loadable';
import { ServerStyleSheet } from 'styled-components';
import {
LoadableCaptureProvider,
preloadAllLoadables,
} from 'meteor/npdev:react-loadable';
preloadAllLoadables().then(() => {
onPageLoad(async (sink) => {
const context = {};
const sheet = new ServerStyleSheet();
const loadableHandle = {};
const routes = (await import('../both/routes.js')).default;
const App = (props) => (
<StaticRouter location={props.location} context={context}>
{routes}
</StaticRouter>
);
const modules = [];
// const html = renderToNodeStream((
const html = renderToString(
<LoadableCaptureProvider handle={loadableHandle}>
<App location={sink.request.url} />
</LoadableCaptureProvider>,
);
// we have a list of modules here, hopefully Meteor will allow to add them to bundle
// console.log(modules);
sink.renderIntoElementById('app', html);
sink.appendToBody(loadableHandle.toScriptTag());
const helmet = Helmet.renderStatic();
// console.log(helmet);
sink.appendToHead(helmet.meta.toString());
sink.appendToHead(helmet.title.toString());
sink.appendToHead(helmet.link.toString());
sink.appendToHead(sheet.getStyleTags());
});
});
client index.js
import { Meteor } from 'meteor/meteor';
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, withRouter } from 'react-router-dom';
import { onPageLoad } from 'meteor/server-render';
import { createBrowserHistory } from 'history';
import { preloadLoadables } from 'meteor/npdev:react-loadable';
console.log('hi');
const history = createBrowserHistory();
/**
* If browser back button was used, flush cache
* This ensures that user will always see an accurate, up-to-date view based on their state
* https://stackoverflow.com/questions/8788802/prevent-safari-loading-from-cache-when-back-button-is-clicked
*/
(function () {
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
})();
onPageLoad(async () => {
const routes = (await import('../both/routes.js')).default;
const App = () => (
<>
<Router history={history}>
<div>{routes}</div>
</Router>
</>
);
preloadLoadables().then(() => {
ReactDOM.hydrate(<App />, document.getElementById('app'));
});
});
What I am trying to determine is what exactly react loadable does. I am wanting to separate my bundle so I can only load code via SSR when it is needed. Right now I have quite a low score on lighthouse for page speed.
The code that I have here works.
But what I expected to happen was have a separate request to grab more js for the loadable component when it is requested. So it's not in the initial bundle. Is this not how this package works.
Could someone one help me me understand this better.
Thanks for any help ahead of time
I am trying to tidy up my routes. I would like to have 1 file,index.ts, to export all my routes from. I have seen something similar done in plain JavaScript but not sure on the syntax in typescript.
The error I get is: TypeError: Router.use() requires a middleware function but got a Object
(old but works)BaseRoutes.ts
import * as express from 'express';
import {PostRoutes} from '../PostRoutes';
import {CspRoutes} from '../CspRoutes';
import {CustomerPreferenceRoutes} from '../CustomerPreferenceRoutes';
import { SalesOrderRoutes } from '../SalesOrderRoutes';
let app = express();
const BASE_API: string = '/api/v2';
class BaseRoutes{
get routes(){
app.use(BASE_API, new PostRoutes().routes);
app.use(BASE_API, new CspRoutes().routes);
app.use(BASE_API, new CustomerPreferenceRoutes().routes);
app.use(BASE_API, new SalesOrderRoutes().routes);
return app;
}
}
export {BaseRoutes}
(new does not work)BaseRoutes.ts
import * as express from 'express';
let routes = require('../index');
let app = express();
const BASE_API: string = '/api/v2';
class BaseRoutes{
get routes(){
app.use(BASE_API,routes);
return app;
}
}
export {BaseRoutes}
PostRoutes.ts
import * as express from 'express';
import {PostController} from '../../controllers/PostController'
let router = express.Router();
class PostRoutes{
private _postController:PostController;
constructor(){
this._postController = new PostController();
}
get routes(){
let controller = this._postController
router.get('/posts',controller.retrieve)
router.get('/posts/:_id',controller.findById)
return router;
}
}
export{PostRoutes};
index.ts
export * from './PostRoutes';
export * from './SalesOrderRoutes';
It is because you messed up your imports.
export * from './PostRoutes';
export * from './SalesOrderRoutes';
You are re-exporting all the exports from PostRoutes and SalesOrderRoutes etc. , so when you finally import it in BaseRoutes , you actually import all the constructors you exported in each route.
What you want to do is:
import { PostRoutes, SalesOrderRoutes } from '../index';
And then use() each route explicitly.
Edit: You can read more about Typescript modules and Javascript modules
I am new to react/redux I little confused with server side rending in react/redux,
Yes i saw some example on the internet but when i tried with mock api with external server , server side rendering is not working .
cat.js
import React from 'react';
import {render} from 'react-dom';
import {connect} from 'react-redux';
import * as mockApi from '../Actions/mockActions';
class Cat extends React.Component{
componentWillMount(){
this.props.getMockApi();
}
render(){
return(
<div>
Hello Dude
{this.props.mock.data.map((data,i) => {
return <li key={i}>{data.email}</li>
})}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
mock:state.mock
}
};
const mapDispatchToProps = (dispatch) => {
return {
getMockApi:() => dispatch(mockApi.getMockData())
}
};
export default connect(mapStateToProps,mapDispatchToProps)(Cat);
mockActions.js
import axios from 'axios';
import * as types from './actionTypes';
export function getMockData() {
return dispatch => {
return axios.get('http://jsonplaceholder.typicode.com/users').then(response => {
dispatch(setThisData(response.data))
})
}
}
export function setThisData(data) {
return {
type:types.MOCK_API,
payload:data
}
}
App.js
import React from 'react';
import {render} from 'react-dom';
import Cat from './components/cat'
import {Provider} from 'react-redux';
import configureStore from './Store/configureStore';
import { createStore ,applyMiddleware,compose} from 'redux';
import counterApp from './Reducers'
import thunk from 'redux-thunk';
if(typeof window !== 'undefined'){
// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__
// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__
const store = createStore(counterApp, preloadedState, compose(applyMiddleware(thunk)))
render(
<Provider store={store} >
<Cat/>
</Provider>
,
document.getElementById('app')
)
}
devServer.js
import express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware'
import webpackHotMidleware from 'webpack-hot-middleware';
import bodyParser from 'body-parser';
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux';
import counterApp from '../../src/client/ReduxServer/Reducers';
import App from '../../src/client/ReduxServer/components/cat';
import { renderToString } from 'react-dom/server'
import webpackConfig from '../../webpack.config.dev';
let app = express();
app.use(bodyParser.json());
app.use(express.static('public'))
const compiler = webpack(webpackConfig);
app.use(webpackMiddleware(compiler, {
hot: true,
publicPath: webpackConfig.output.publicPath,
noInfo: true
}));
app.use(webpackHotMidleware(compiler));
// app.get('/*', (req, res) => {
// res.sendFile(path.join(__dirname, '../../index.html'))
// });
//Redux Start
app.use(handleRender);
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
function renderFullPage(html, preloadedState) {
console.log(preloadedState)
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="app">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script>
<script src="bundle.js"></script>
</body>
</html>
`
}
//Redux Ends
app.listen(3000, () => {
console.log('Listening')
});
Right now this will only server render the hello dude but not the mock Api call data .I know that missed to fetch the data from server side but the point is what will i do If ihave to render a two components and that component has 5 api reuqest ,And how to fecth the correct api Request
Right Now My client Side Prefecthed state will look like this
window.__PRELOADED_STATE__ = {"mock":{"data":[]}}
Ok, to make this clear, you've created the code to handle server rendering. However, it doesn't load the data that is supposed to be fetched right?
You've done the first step, great! The next step is to load the actual dynamic data to the store. Let's look at this code here
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
What happened is that you created a store. The store is used to render the html into a string. Then you get the store state and put it into preloadedState.
This is great accept that renderToString will not call this.props.getMockApi(); as you would expect.
Instead, you have to fetch the state before you call renderToString();
In this case, what you could do is as following. (Note that this is just an example, you probably want to use something more general in production, especially if you use something like react-router.)
import * as mockApi from '../Actions/mockActions';
function handleRender(req, res) {
const store = createStore(counterApp);
store.dispatch(mockApi.getMockData())
// And since you used redux-thunk, it should return a promise
.then(() => {
const html = renderToString(
<Provider store={store}>
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
});
}
Simple isn't it? ;D, nah just joking. This is one part of react where there's not really an exact solution to the problem yet.
Personally, if I had the choice to go back in time, I'd tell myself to learn other stuff other than server rendering. There are other techniques such as code splitting, lazy loading, etc that I could've used instead. With server rendering, if the javascript arrives long after the user has seen the initial page, they might get frustrated by other things that require js. For example in my case, some links are not working, some buttons don't do anything, etc.
I'm not saying that server rendering is not good. It's an interesting technique, just that there are other techniques that are more beneficial to learn first (Oh, and server rendering basically locks you to use nodejs for your backend). Good luck to you :)
I'm having a strange issue when exporting my routes. For some reason, this code works for me:
app.js
import Koa from 'koa'
import routes from './routes/index'
const app = new Koa()
app.use(routes)
app.listen(3000, () => {
console.log('Server listening at http://localhost:3000')
})
export default app
routes/index.js
import Router from 'koa-router'
const router = new Router()
router.get('/', async ctx => {
await ctx.render('index')
})
export default router.routes()
but when I just export the routes function and then try to call it in app.js, I get an error:
app.js
import Koa from 'koa'
import routes from './routes/index'
const app = new Koa()
app.use(routes())
app.listen(3000, () => {
console.log('Server listening at http://localhost:3000')
})
export default app
routes/index.js
import Router from 'koa-router'
const router = new Router()
router.get('/', async ctx => {
await ctx.render('index')
})
export default router.routes
Why doesn't it work when I do it the second way?
You probably would like to export a bound function, so this inside it would refer to a router object.
It could be done nicely with a bind operator. I believe it's already available since you are using async/await.
import Router from 'koa-router'
const router = new Router()
router.get('/', async ctx => {
await ctx.render('index')
})
export default ::router.routes
You have to add a method:
router.allowedMethods()
like this:
app.use(router.routes(), router.allowedMethods())
The following contents of the application.js file report that "home" being imported is undefined.
import {home} from "./routes/index"
console.log(JSON.stringify(home, null, 4))
The content of index.js are as follows:
export * from "./home.js"
The content of home.js are as follows:
export const type = "GET"
export const route = "/"
export const middleware = [];
export const action = function(req, res) {
res.send("Testing custom routes");
}
A picture of the directory structure is as follows:
You're not exporting anything named home. If you want to attach everything you are exporting to a variable named home then use as.
import * as home from './routes/index';
See here for more information on import/export.
You could structure your code like so to achieve the effect you want:
application.js
import { home } from './routes';
home.js
const type = "GET"
const route = "/"
const middleware = [];
const action = function(req, res) {
res.send("Testing custom routes");
}
export default {
type,
route,
middleware,
action
};
index.js
import * as home from './home.js';
export default {
home
};