PR-049111: making mayor change for add support to prefix url.

This commit is contained in:
Alejandro Lembke Barrientos 2023-02-10 21:09:27 +00:00
parent 8ddd290adb
commit e70d0a01ca
17 changed files with 82 additions and 59 deletions

View File

@ -3,4 +3,8 @@ ENV= #Default production
#App Port #App Port
PORT= #Default 80 PORT= #Default 80
#PUBLIC URL #PUBLIC URL
PUBLIC_URL= #Default / PUBLIC_URL= #Default 'auto'
#Prefix URL
PREFIX_URL= #Default ''
#ONLY EXACT PATH
ONLY_EXACT_PATH= #Default false

View File

@ -25,13 +25,17 @@ You will need to create a new .env file at the root of the project for global co
This is an exaple of config. This is an exaple of config.
``` ```
#Environment #Environment
ENV=development #Default production ENV= #Default production
#App Port #App Port
PORT=3000 #Default 80 PORT= #Default 80
#PUBLIC URL #PUBLIC URL
#PUBLIC_URL= #Default / PUBLIC_URL= #Default 'auto'
#Prefix URL
PREFIX_URL= #Default ''
#ONLY EXACT PATH
ONLY_EXACT_PATH= #Default false
``` ```
The default environment is production, the app port defauld is 80 and the default public url is "/". The default environment is production, the app port defauld is 80 and the default public url is "auto", use prefix url if you want a prefix on base url, use exact path to validate if you want to have strict exact paths.
### For Development ### For Development
In the terminal run: In the terminal run:

View File

@ -102,7 +102,7 @@ if(!cleanGitHistory) process.exit(-1);
console.log("Congratulations! You are ready. Follow the following commands to start"); console.log("Congratulations! You are ready. Follow the following commands to start");
console.log(`cd ${repoName}`); console.log(`cd ${repoName}`);
console.log('Create a .env file with ENV=development(defauld: production), PORT=3000 (default: 80), PUBLIC_URL=your_public_url(optional)(default: /)'); console.log('Create a .env file with ENV=development(defauld: production), PORT=3000 (default: 80), PUBLIC_URL=your_public_url(optional)(default: "auto"), PREFIX_URL=your_prefix_url(optional)(default: ""), ONLY_EXACT_PATH=true(optional)(default: false)');
console.log(`Then you can run: npm start:dev`); console.log(`Then you can run: npm start:dev`);
const deleteFolders = isWin ? runCommand(deleteFoldersCommandWindows) : runCommand(deleteFoldersCommand); const deleteFolders = isWin ? runCommand(deleteFoldersCommandWindows) : runCommand(deleteFoldersCommand);

View File

@ -1,11 +1,15 @@
export const config = {
ENV: process.env.ENV,
PORT: process.env.PORT,
PUBLIC_URL: process.env.PUBLIC_URL,
};
export const deFaultValues = { export const deFaultValues = {
ENV: 'production', ENV: 'production',
PORT: 3000, PORT: 80,
PUBLIC_URL: '/', PUBLIC_URL: 'auto',
PREFIX_URL: '',
ONLY_EXACT_PATH: false,
} }
export const config = {
ENV: process.env.ENV ? process.env.ENV : deFaultValues.ENV,
PORT: process.env.PORT ? process.env.PORT : deFaultValues.PORT,
PUBLIC_URL: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : deFaultValues.PUBLIC_URL,
PREFIX_URL: process.env.PREFIX_URL ? process.env.PREFIX_URL : deFaultValues.PREFIX_URL,
ONLY_EXACT_PATH: process.env.ONLY_EXACT_PATH ? process.env.ONLY_EXACT_PATH === 'true' : deFaultValues.ONLY_EXACT_PATH,
};

View File

@ -3,6 +3,9 @@ module.exports = {
"testEnvironment": "jsdom", "testEnvironment": "jsdom",
moduleNameMapper: { moduleNameMapper: {
"\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/__mocks__/fileMock.ts", "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/__mocks__/fileMock.ts",
"@components": "<rootDir>/src/frontend/components/",
"@styles": "<rootDir>/src/frontend/styles/",
"@config": "<rootDir>/config/",
"\\.(css|sass|scss|less)$": "identity-obj-proxy" "\\.(css|sass|scss|less)$": "identity-obj-proxy"
}, },
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "@aleleba/create-react-ssr", "name": "@aleleba/create-react-ssr",
"version": "3.5.7", "version": "3.6.0",
"description": "Starter Kit of server side render of react", "description": "Starter Kit of server side render of react",
"bin": "./bin/cli.js", "bin": "./bin/cli.js",
"main": "src/server/index", "main": "src/server/index",

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -2,3 +2,7 @@ declare module "*.svg" {
const content: any; const content: any;
export default content; export default content;
} }
declare module "@config" {
export const config: any;
}

View File

@ -1,12 +1,11 @@
import React from 'react'; import React from 'react';
import logo from '../logo.svg';
import './InitialComponent.scss'; import './InitialComponent.scss';
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const InitialComponent = () => ( const InitialComponent = () => (
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
<img src={logo} className="App-logo" alt="logo" /> <img src="assets/img/logo.svg" className="App-logo" alt="logo" />
<p> <p>
Edit <code>src/frontend/InitialComponent.jsx</code> and save to reload. Edit <code>src/frontend/InitialComponent.jsx</code> and save to reload.
</p> </p>

View File

@ -6,7 +6,7 @@ import { Link } from "react-router-dom";
const OtherComponent = () => ( const OtherComponent = () => (
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
<img src={logo} className="App-logo" alt="logo" /> <img src="assets/img/logo.svg" className="App-logo" alt="logo" />
<p> <p>
Edit <code>src/frontend/OtherComponent.jsx</code> and save to reload. Edit <code>src/frontend/OtherComponent.jsx</code> and save to reload.
</p> </p>

View File

@ -28,7 +28,7 @@ interface IHot {
accept: any accept: any
} }
const { ENV } = config; const { ENV, PREFIX_URL } = config;
const preloadedState = window.__PRELOADED_STATE__; const preloadedState = window.__PRELOADED_STATE__;
const store = setStore({ initialState: preloadedState }); const store = setStore({ initialState: preloadedState });
@ -41,7 +41,7 @@ if(ENV === 'development') {
const root = createRoot(container); const root = createRoot(container);
root.render( root.render(
<Provider store={store}> <Provider store={store}>
<Router> <Router basename={PREFIX_URL}>
<App /> <App />
</Router> </Router>
</Provider> </Provider>
@ -51,7 +51,7 @@ if(ENV === 'development') {
// add "const root" to be able to rerender. // add "const root" to be able to rerender.
ENV === 'production' && hydrateRoot(container, ENV === 'production' && hydrateRoot(container,
<Provider store={store}> <Provider store={store}>
<Router> <Router basename={PREFIX_URL}>
<App /> <App />
</Router> </Router>
</Provider>, </Provider>,

View File

@ -12,5 +12,4 @@ const INITIAL_COMPONENT = {
element: <InitialComponent />, element: <InitialComponent />,
}; };
export default [ INITIAL_COMPONENT, OTHER_COMPONENT ]; export default [ INITIAL_COMPONENT, OTHER_COMPONENT ];

View File

@ -2,7 +2,7 @@
import express from 'express'; import express from 'express';
import webpack from 'webpack'; import webpack from 'webpack';
import helmet from 'helmet'; import helmet from 'helmet';
import { config } from '../../config'; import { config } from '@config';
//Dependencies of HotReloading //Dependencies of HotReloading
import webpackConfig from '../../webpack.config.dev'; import webpackConfig from '../../webpack.config.dev';
@ -24,9 +24,9 @@ import { getHashManifest, haveVendorsCss } from './utilsServer';
//App //App
import App from '../frontend/components/App'; import App from '../frontend/components/App';
const { ENV, PORT } = config; const { ENV, PORT, PREFIX_URL, ONLY_EXACT_PATH } = config;
const routesUrls = routes.map( route => route.path); const routesUrls = routes.map( route => route.path );
const app = express(); const app = express();
@ -47,6 +47,7 @@ if(ENV === 'development'){
}else{ }else{
const baseUrl = __dirname.replace(/\/server(.*)/,''); const baseUrl = __dirname.replace(/\/server(.*)/,'');
const fullURL = `${baseUrl}` ; const fullURL = `${baseUrl}` ;
console.log(fullURL)
app app
.use((req, res, next) => { .use((req, res, next) => {
if(!req.hashManifest) req.hashManifest = getHashManifest(); if(!req.hashManifest) req.hashManifest = getHashManifest();
@ -102,17 +103,21 @@ const setResponse = (html, preloadedState, manifest) => {
}; };
const renderApp = (req, res, next) => { const renderApp = (req, res, next) => {
if(routesUrls.includes(req.url)){ const store = setStore({ initialState });
const store = setStore({ initialState }); const preloadedState = store.getState();
const preloadedState = store.getState(); const html = renderToString(
const html = renderToString( // @ts-ignore:next-line
// @ts-ignore:next-line <Provider store={store}>
<Provider store={store}> <StaticRouter location={`${PREFIX_URL}${req.url}`} basename={PREFIX_URL}>
<StaticRouter location={req.url}> <App />
<App /> </StaticRouter>
</StaticRouter> </Provider>
</Provider> );
); if(ONLY_EXACT_PATH){
if(routesUrls.includes(req.url)){
res.send(setResponse(html, preloadedState, req.hashManifest));
}
} else {
res.send(setResponse(html, preloadedState, req.hashManifest)); res.send(setResponse(html, preloadedState, req.hashManifest));
} }
next(); next();
@ -121,7 +126,6 @@ const renderApp = (req, res, next) => {
app app
.get('*', renderApp); .get('*', renderApp);
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`); console.log(`Server running on port ${PORT}`);
}); });

View File

@ -1,7 +1,7 @@
import fs from 'fs'; import fs from 'fs';
import { config } from '../../config'; import { config } from '../../config';
const { ENV } = config; const { ENV } = config
export const getHashManifest = () => { export const getHashManifest = () => {
try { try {
@ -17,7 +17,7 @@ export const getHashManifest = () => {
export const haveVendorsCss = (manifest, memoryFs) => { export const haveVendorsCss = (manifest, memoryFs) => {
try { try {
const baseUrl = __dirname.replace(/\/server(.*)/,''); const baseUrl = __dirname.replace(/\/server(.*)/,'');
const fullURL = `${baseUrl}${manifest ? manifest['vendors.css'] : '/build/assets/vendors.css'}`; const fullURL = `${baseUrl}${manifest ? `/${manifest['vendors.css']}` : '/build/assets/vendors.css'}`;
ENV === 'production' && fs.readFileSync(fullURL).toString(); ENV === 'production' && fs.readFileSync(fullURL).toString();
ENV === 'development' && memoryFs.readFileSync(fullURL).toString(); ENV === 'development' && memoryFs.readFileSync(fullURL).toString();
return true return true

View File

@ -21,10 +21,10 @@ const config: Configuration = {
resolve: { resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
alias: { alias: {
'@app': path.resolve(__dirname, 'src/frontend/components/App'),
'@components': path.resolve(__dirname, 'src/frontend/components/'), '@components': path.resolve(__dirname, 'src/frontend/components/'),
'@styles': path.resolve(__dirname, 'src/frontend/styles/'), '@styles': path.resolve(__dirname, 'src/frontend/styles/'),
} '@config': path.resolve(__dirname, 'config/'),
},
}, },
module: { module: {
rules: [ rules: [
@ -58,7 +58,7 @@ const config: Configuration = {
test: fontsAndImagesExtensions, test: fontsAndImagesExtensions,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '/assets/[name].[ext]', name: 'assets/[name].[ext]',
emitFile: false, emitFile: false,
}, },
}, },

View File

@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { deFaultValues } from './config'; import { config as envConfig } from './config';
import webpack, { Configuration } from 'webpack'; import webpack, { Configuration } from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
@ -33,18 +33,19 @@ if(fs.existsSync(`${ROOT_DIR}/../public/img`)){
} }
const config: Configuration = { const config: Configuration = {
entry: ['webpack-hot-middleware/client?path=/reload_wss&timeout=2000&reload=true&autoConnect=true', `${ROOT_DIR}/../src/frontend/index.tsx`], entry: [`webpack-hot-middleware/client?path=${envConfig.PREFIX_URL}/reload_wss&timeout=2000&reload=true&autoConnect=true`, `${ROOT_DIR}/../src/frontend/index.tsx`],
output: { output: {
path: BUILD_DIR, path: BUILD_DIR,
filename: 'assets/app.js', filename: 'assets/app.js',
publicPath: deFaultValues.PUBLIC_URL, publicPath: envConfig.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias: { alias: {
'@components': path.resolve(__dirname, 'src/frontend/components/'), '@components': path.resolve(__dirname, '../src/frontend/components/'),
'@styles': path.resolve(__dirname, 'src/frontend/styles/'), '@styles': path.resolve(__dirname, '../src/frontend/styles/'),
} '@config': path.resolve(__dirname, '../config/'),
},
}, },
devtool: 'inline-source-map', devtool: 'inline-source-map',
mode: 'development', mode: 'development',
@ -92,7 +93,7 @@ const config: Configuration = {
}), }),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.EnvironmentPlugin({ new webpack.EnvironmentPlugin({
...deFaultValues, ...envConfig,
}), }),
new CopyPlugin({ new CopyPlugin({
patterns: copyPatterns patterns: copyPatterns

View File

@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { deFaultValues } from './config'; import { config as envConfig } from './config';
import webpack from 'webpack'; import webpack from 'webpack';
import CompressionWebpackPlugin from 'compression-webpack-plugin'; import CompressionWebpackPlugin from 'compression-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin';
@ -46,13 +46,14 @@ const frontendConfig = {
output: { output: {
path: BUILD_DIR, path: BUILD_DIR,
filename: 'assets/app-[name]-[fullhash].js', filename: 'assets/app-[name]-[fullhash].js',
publicPath: deFaultValues.PUBLIC_URL, publicPath: envConfig.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias: { alias: {
'@components': path.resolve(__dirname, 'src/frontend/components/'), '@components': path.resolve(__dirname, 'src/frontend/components/'),
'@styles': path.resolve(__dirname, 'src/frontend/styles/'), '@styles': path.resolve(__dirname, 'src/frontend/styles/'),
'@config': path.resolve(__dirname, 'config/'),
} }
}, },
mode: 'production', mode: 'production',
@ -100,6 +101,7 @@ const frontendConfig = {
}), }),
new WebpackManifestPlugin({ new WebpackManifestPlugin({
fileName: 'assets/manifest-hash.json', fileName: 'assets/manifest-hash.json',
publicPath: envConfig.PREFIX_URL,
}), }),
new CleanWebpackPlugin({ new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [ cleanOnceBeforeBuildPatterns: [
@ -109,7 +111,7 @@ const frontendConfig = {
}), }),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.EnvironmentPlugin({ new webpack.EnvironmentPlugin({
...deFaultValues, ...envConfig,
}), }),
new CopyPlugin({ new CopyPlugin({
patterns: copyPatterns patterns: copyPatterns
@ -154,13 +156,14 @@ const serverConfig = {
output: { output: {
path: path.resolve(__dirname, 'build'), path: path.resolve(__dirname, 'build'),
filename: 'server/app-[name].js', filename: 'server/app-[name].js',
publicPath: deFaultValues.PUBLIC_URL, publicPath: envConfig.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias: { alias: {
'@components': path.resolve(__dirname, 'src/frontend/components/'), '@components': path.resolve(__dirname, 'src/frontend/components/'),
'@styles': path.resolve(__dirname, 'src/frontend/styles/'), '@styles': path.resolve(__dirname, 'src/frontend/styles/'),
'@config': path.resolve(__dirname, 'config/'),
} }
}, },
mode: 'production', mode: 'production',
@ -208,12 +211,10 @@ const serverConfig = {
}), }),
new WebpackManifestPlugin({ new WebpackManifestPlugin({
fileName: 'assets/manifest-hash.json', fileName: 'assets/manifest-hash.json',
publicPath: envConfig.PREFIX_URL,
}), }),
new CleanWebpackPlugin(), new CleanWebpackPlugin(),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.EnvironmentPlugin({
...deFaultValues,
}),
new InjectManifest({ new InjectManifest({
swSrc: './service-worker.ts', swSrc: './service-worker.ts',
swDest: 'service-worker.js', swDest: 'service-worker.js',