mirror of
https://github.com/aleleba/create-react-ssr.git
synced 2025-09-13 16:46:40 -06:00
PR-753737: Cambiando la carpeta src a client y moviendo todo a una carpeta dentro de client llamada src.
This commit is contained in:
6
client/src/frontend/components/App.tsx
Normal file
6
client/src/frontend/components/App.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import React from 'react';
|
||||
import PrincipalRoutes from './PrincipalRoutes';
|
||||
|
||||
const App = () => <PrincipalRoutes />;
|
||||
|
||||
export default App;
|
5
client/src/frontend/components/InitialComponent.jsx
Normal file
5
client/src/frontend/components/InitialComponent.jsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const InitialComponent = () => <h1>Hello React!</h1>;
|
||||
|
||||
export default InitialComponent;
|
5
client/src/frontend/components/OtherComponent.jsx
Normal file
5
client/src/frontend/components/OtherComponent.jsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const OtherComponent = () => <h1>Other Component!</h1>;
|
||||
|
||||
export default OtherComponent;
|
11
client/src/frontend/components/PrincipalRoutes.jsx
Normal file
11
client/src/frontend/components/PrincipalRoutes.jsx
Normal file
@ -0,0 +1,11 @@
|
||||
//Router
|
||||
import { useRoutes } from 'react-router-dom';
|
||||
//Routes
|
||||
import routes from '../../routes';
|
||||
|
||||
const PrincipalRoutes = () => {
|
||||
let element = useRoutes(routes);
|
||||
return element;
|
||||
};
|
||||
|
||||
export default PrincipalRoutes;
|
75
client/src/frontend/index.tsx
Normal file
75
client/src/frontend/index.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
import { hydrateRoot } from 'react-dom/client';
|
||||
// Router
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
// Redux
|
||||
import { Provider } from 'react-redux';
|
||||
import { IInitialState } from './reducers/index.js';
|
||||
import setStore from './setStore.js';
|
||||
import { config } from '../../config';
|
||||
|
||||
import './styles/global.sass';
|
||||
import App from './components/App';
|
||||
import serviceWorkerRegistration from '../../serviceWorkerRegistration';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__PRELOADED_STATE__?: IInitialState;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface NodeModule {
|
||||
hot?: IHot;
|
||||
}
|
||||
}
|
||||
|
||||
interface IHot {
|
||||
accept: any
|
||||
}
|
||||
|
||||
const { env } = config;
|
||||
|
||||
const preloadedState = window.__PRELOADED_STATE__;
|
||||
const store = setStore({ initialState: preloadedState });
|
||||
|
||||
delete window.__PRELOADED_STATE__;
|
||||
|
||||
const container = document.getElementById('app')!;
|
||||
|
||||
// add "const root" to be able to rerender.
|
||||
hydrateRoot(container,
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
</Provider>,
|
||||
// Add this comment to update later app and remove warning
|
||||
/* {
|
||||
onRecoverableError: (error) => {
|
||||
console.error("recoverable", error);
|
||||
}
|
||||
}, */
|
||||
);
|
||||
|
||||
// Use root.render to update later the app
|
||||
/* root.render(
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
</Provider>
|
||||
); */
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: http://bit.ly/CRA-PWA
|
||||
//serviceWorker.register();
|
||||
|
||||
if((env) && (env === 'production')){
|
||||
serviceWorkerRegistration();
|
||||
}
|
||||
|
||||
if(module.hot){
|
||||
module.hot.accept();
|
||||
}
|
13
client/src/frontend/reducers/index.ts
Normal file
13
client/src/frontend/reducers/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import testReducer, { ITestReducer } from './testReducer';
|
||||
|
||||
export interface IInitialState {
|
||||
testReducer?: ITestReducer | undefined
|
||||
}
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
// Here comes the reducers
|
||||
testReducer
|
||||
});
|
||||
|
||||
export default rootReducer;
|
2
client/src/frontend/reducers/initialState.js
Normal file
2
client/src/frontend/reducers/initialState.js
Normal file
@ -0,0 +1,2 @@
|
||||
let initialState = {};
|
||||
export default initialState;
|
22
client/src/frontend/reducers/testReducer.ts
Normal file
22
client/src/frontend/reducers/testReducer.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export interface ITestReducer {
|
||||
hello: any | undefined
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
hello: 'world'
|
||||
};
|
||||
|
||||
const testReducer = (state = initialState, action: { type: any; payload: { hello: any; }; }) => {
|
||||
switch (action.type){
|
||||
case 'CHANGE_HELLO': {
|
||||
const newHello = action.payload.hello;
|
||||
return {
|
||||
hello: newHello
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default testReducer;
|
26
client/src/frontend/setStore.js
Normal file
26
client/src/frontend/setStore.js
Normal file
@ -0,0 +1,26 @@
|
||||
// Redux
|
||||
import { createStore } from 'redux'; //, applyMiddleware
|
||||
// import { Provider } from 'react-redux';
|
||||
import { composeWithDevTools as composeWithDevToolsWeb } from 'redux-devtools-extension';
|
||||
import { config } from '../../config';
|
||||
import reducer from './reducers';
|
||||
|
||||
const { env } = config;
|
||||
|
||||
const composeEnhancers = composeWithDevToolsWeb({
|
||||
// Specify here name, actionsBlacklist, actionsCreators and other options
|
||||
});
|
||||
|
||||
const setStore = ({ initialState }) => {
|
||||
const store = env === 'development' ? createStore(
|
||||
reducer,
|
||||
initialState,
|
||||
composeEnhancers(),
|
||||
) : createStore(
|
||||
reducer,
|
||||
initialState,
|
||||
);
|
||||
return store;
|
||||
};
|
||||
|
||||
export default setStore;
|
6
client/src/frontend/styles/global.sass
Normal file
6
client/src/frontend/styles/global.sass
Normal file
@ -0,0 +1,6 @@
|
||||
$base-color: #c6538c
|
||||
$color: rgba(black, 0.88)
|
||||
|
||||
body
|
||||
background-color: $base-color
|
||||
color: $color
|
16
client/src/routes/index.js
Normal file
16
client/src/routes/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import InitialComponent from '../frontend/components/InitialComponent';
|
||||
import OtherComponent from '../frontend/components/OtherComponent';
|
||||
|
||||
const OTHER_COMPONENT = {
|
||||
path: '/other-component',
|
||||
element: <OtherComponent />
|
||||
};
|
||||
|
||||
const INITIAL_COMPONENT = {
|
||||
path: '/',
|
||||
element: <InitialComponent />,
|
||||
};
|
||||
|
||||
|
||||
export default [ INITIAL_COMPONENT, OTHER_COMPONENT ];
|
13
client/src/server/getHashManifest.js
Normal file
13
client/src/server/getHashManifest.js
Normal file
@ -0,0 +1,13 @@
|
||||
import fs from 'fs';
|
||||
|
||||
const getHashManifest = () => {
|
||||
try {
|
||||
const baseUrl = __dirname.replace(/\/client(.*)/,'');
|
||||
const fullURL = `${baseUrl}/client/build/assets/manifest-hash.json` ;
|
||||
return JSON.parse(fs.readFileSync(fullURL));
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
export default getHashManifest;
|
36
client/src/server/index.js
Normal file
36
client/src/server/index.js
Normal file
@ -0,0 +1,36 @@
|
||||
require('dotenv').config();
|
||||
|
||||
require('ignore-styles');
|
||||
|
||||
//require('webpack-node-externals')();
|
||||
|
||||
require('@babel/register')({
|
||||
'presets': [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
"@babel/preset-typescript",
|
||||
// '@babel/preset-flow',
|
||||
]
|
||||
});
|
||||
|
||||
require('asset-require-hook')({
|
||||
extensions: [
|
||||
// images
|
||||
'jpg',
|
||||
'png',
|
||||
'svg',
|
||||
'gif',
|
||||
// videos
|
||||
'mp4',
|
||||
'avi',
|
||||
// typography
|
||||
'ttf',
|
||||
'otf',
|
||||
'eot',
|
||||
// files
|
||||
'pdf'
|
||||
],
|
||||
name: '/assets/[hash].[ext]',
|
||||
});
|
||||
|
||||
require('./server');
|
121
client/src/server/server.js
Normal file
121
client/src/server/server.js
Normal file
@ -0,0 +1,121 @@
|
||||
//Dependencies of Server
|
||||
import express from 'express';
|
||||
import { config } from '../../config';
|
||||
import webpack from 'webpack';
|
||||
import helmet from 'helmet';
|
||||
|
||||
//Dependencies of HotReloading
|
||||
import webpackConfig from '../../webpack.config.dev';
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware';
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware';
|
||||
|
||||
//Dependencies of SSR
|
||||
import React from 'react';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
//Router
|
||||
import { StaticRouter } from 'react-router-dom/server';
|
||||
import routes from '../routes';
|
||||
//Redux
|
||||
import { Provider } from 'react-redux';
|
||||
import setStore from '../frontend/setStore.js';
|
||||
import initialState from '../frontend/reducers/initialState';
|
||||
//Get Hashes
|
||||
import getHashManifest from './getHashManifest';
|
||||
//App
|
||||
import App from '../frontend/components/App';
|
||||
|
||||
const { env, port } = config;
|
||||
|
||||
const routesUrls = routes.map( route => route.path);
|
||||
|
||||
const app = express();
|
||||
|
||||
if(env === 'development'){
|
||||
const compiler = webpack(webpackConfig);
|
||||
const serverConfig = {
|
||||
serverSideRender: true,
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
};
|
||||
|
||||
app
|
||||
.use(webpackDevMiddleware(compiler, serverConfig))
|
||||
.use(webpackHotMiddleware(compiler, {
|
||||
path: '/reload_wss',
|
||||
heartbeat: 1000,
|
||||
}));
|
||||
}else{
|
||||
const baseUrl = __dirname.replace(/\/client(.*)/,'');
|
||||
const fullURL = `${baseUrl}/client/build` ;
|
||||
app
|
||||
.use((req, res, next) => {
|
||||
if(!req.hashManifest) req.hashManifest = getHashManifest();
|
||||
next();
|
||||
})
|
||||
.use(express.static(fullURL))
|
||||
.use(helmet())
|
||||
.use(helmet.permittedCrossDomainPolicies())
|
||||
.use(helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
...helmet.contentSecurityPolicy.getDefaultDirectives(),
|
||||
'script-src': ['\'self\'', '\'unsafe-inline\''],//"example.com"
|
||||
},
|
||||
},
|
||||
}))
|
||||
.disable('x-powered-by');
|
||||
}
|
||||
|
||||
const setResponse = (html, preloadedState, manifest) => {
|
||||
const mainStyles = manifest ? manifest['main.css'] : 'assets/app.css';
|
||||
const mainBuild = manifest ? manifest['main.js'] : 'assets/app.js';
|
||||
const vendorBuild = manifest ? manifest['vendors.js'] : 'assets/vendor.js';
|
||||
|
||||
return(`
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- <link rel="shortcut icon" href="favicon.ico"> -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link href="${mainStyles}" rel="stylesheet" type="text/css"></link>
|
||||
<title>App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">${html}</div>
|
||||
<script>
|
||||
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
|
||||
</script>
|
||||
<script src="${mainBuild}" type="text/javascript"></script>
|
||||
<script src="${vendorBuild}" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
};
|
||||
|
||||
const renderApp = (req, res, next) => {
|
||||
if(routesUrls.includes(req.url)){
|
||||
const store = setStore({ initialState });
|
||||
const preloadedState = store.getState();
|
||||
const html = renderToString(
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={req.url}>
|
||||
<App />
|
||||
</StaticRouter>
|
||||
</Provider>
|
||||
);
|
||||
res.send(setResponse(html, preloadedState, req.hashManifest));
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
app
|
||||
.get('*', renderApp);
|
||||
|
||||
|
||||
app.listen(port, (err) => {
|
||||
if(err) console.error(err);
|
||||
else console.log(`Server running on port ${port}`);
|
||||
});
|
Reference in New Issue
Block a user