mirror of
				https://github.com/aleleba/create-react-ssr.git
				synced 2025-10-30 21:51:01 -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