Merge pull request #59 from aleleba/PR-492498

PR-492498: changing some webpack configuration and updating packages.
This commit is contained in:
Alejandro Lembke Barrientos 2022-08-30 11:04:13 -06:00 committed by GitHub
commit 6571b99b5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1336 additions and 1301 deletions

View File

@ -9,8 +9,8 @@ Tech(Library or Framework) | Version |
React (Render Library) | 18.2.0 React (Render Library) | 18.2.0
Redux (Global State Management) | 4.2.0 Redux (Global State Management) | 4.2.0
React Router DOM (Routing) | 6.3.0 React Router DOM (Routing) | 6.3.0
Jest (Testing) | 28.1.3 Jest (Testing) | 29.0.1
Typescript | 4.7.4 Typescript | 4.8.2
## Setup ## Setup
To create a new project run in the terminal: To create a new project run in the terminal:

View File

@ -1,6 +1,11 @@
const config = { export const config = {
env: process.env.ENV ? process.env.ENV : 'production', ENV: process.env.ENV,
port: process.env.PORT ? process.env.PORT : 80, PORT: process.env.PORT,
PUBLIC_URL: process.env.PUBLIC_URL,
}; };
export default config; export const deFaultValues = {
ENV: 'production',
PORT: 80,
PUBLIC_URL: '/',
}

2427
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
{ {
"name": "@aleleba/create-react-ssr", "name": "@aleleba/create-react-ssr",
"version": "3.3.0", "version": "3.4.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",
"scripts": { "scripts": {
"start": "node build/server/app-server.js", "start": "node build/server/app-server.js",
"start:dev": "rm -rf build && webpack --mode=development --config webpack.config.dev.server.ts && node build/server.js", "start:dev": "rm -rf build && webpack --mode=development --config webpack.config.dev.server.ts",
"build": "webpack-cli --config webpack.config.ts", "build": "webpack-cli --config webpack.config.ts",
"lint": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx", "lint": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx",
"lint:fix": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx --fix", "lint:fix": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx --fix",
@ -35,7 +35,7 @@
"asset-require-hook": "^1.2.0", "asset-require-hook": "^1.2.0",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"express": "^4.18.1", "express": "^4.18.1",
"helmet": "^5.1.1", "helmet": "^6.0.0",
"ignore-styles": "^5.0.1", "ignore-styles": "^5.0.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -67,45 +67,46 @@
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0", "@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.4.3",
"@types/jest": "^28.1.7", "@types/jest": "^29.0.0",
"@types/node": "^18.7.11", "@types/node": "^18.7.14",
"@types/react": "^18.0.17", "@types/react": "^18.0.18",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/webpack": "^5.28.0", "@types/webpack": "^5.28.0",
"@types/webpack-hot-middleware": "^2.25.6", "@types/webpack-hot-middleware": "^2.25.6",
"@types/webpack-node-externals": "^2.5.3", "@types/webpack-node-externals": "^2.5.3",
"@typescript-eslint/eslint-plugin": "^5.34.0", "@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.34.0", "@typescript-eslint/parser": "^5.36.1",
"babel-jest": "^28.1.3", "babel-jest": "^29.0.1",
"babel-loader": "^8.2.5", "babel-loader": "^8.2.5",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"compression-webpack-plugin": "^10.0.0", "compression-webpack-plugin": "^10.0.0",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0", "css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "^8.22.0", "eslint": "^8.23.0",
"eslint-plugin-react": "^7.30.1", "eslint-plugin-react": "^7.31.1",
"eslint-webpack-plugin": "^3.2.0", "eslint-webpack-plugin": "^3.2.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^28.1.3", "jest": "^29.0.1",
"jest-environment-jsdom": "^28.1.3", "jest-environment-jsdom": "^29.0.1",
"jest-fetch-mock": "^3.0.3", "jest-fetch-mock": "^3.0.3",
"mini-css-extract-plugin": "^2.6.1", "mini-css-extract-plugin": "^2.6.1",
"react-refresh": "^0.14.0", "react-refresh": "^0.14.0",
"redux-devtools-extension": "^2.13.9", "redux-devtools-extension": "^2.13.9",
"sass": "^1.54.5", "sass": "^1.54.6",
"sass-loader": "^13.0.2", "sass-loader": "^13.0.2",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.5", "terser-webpack-plugin": "^5.3.6",
"ts-loader": "^9.3.1", "ts-loader": "^9.3.1",
"typescript": "^4.7.4", "typescript": "^4.8.2",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"webpack-cli": "^4.10.0", "webpack-cli": "^4.10.0",
"webpack-dev-middleware": "^5.3.3", "webpack-dev-middleware": "^5.3.3",
"webpack-dev-server": "^4.10.0", "webpack-dev-server": "^4.10.1",
"webpack-hot-middleware": "^2.25.2", "webpack-hot-middleware": "^2.25.2",
"webpack-node-externals": "^3.0.0", "webpack-node-externals": "^3.0.0",
"webpack-shell-plugin-next": "^2.2.2",
"workbox-webpack-plugin": "^6.5.4", "workbox-webpack-plugin": "^6.5.4",
"workbox-window": "^6.5.4" "workbox-window": "^6.5.4"
} }

View File

@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { IInitialState } from './reducers/index'; import { IInitialState } from './reducers/index';
import setStore from './setStore'; import setStore from './setStore';
import config from '../../config'; import { config } from '../../config';
import './styles/global.scss'; import './styles/global.scss';
import App from './components/App'; import App from './components/App';
@ -28,7 +28,7 @@ interface IHot {
accept: any accept: any
} }
const { env } = config; const { ENV } = config;
const preloadedState = window.__PRELOADED_STATE__; const preloadedState = window.__PRELOADED_STATE__;
const store = setStore({ initialState: preloadedState }); const store = setStore({ initialState: preloadedState });
@ -37,7 +37,7 @@ delete window.__PRELOADED_STATE__;
const container = document.getElementById('app')!; const container = document.getElementById('app')!;
if(env === 'development') { if(ENV === 'development') {
const root = createRoot(container); const root = createRoot(container);
root.render( root.render(
<Provider store={store}> <Provider store={store}>
@ -49,7 +49,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>
<App /> <App />
@ -72,7 +72,7 @@ env === 'production' && hydrateRoot(container,
</Provider> </Provider>
); */ ); */
if((env) && (env === 'production')){ if((ENV) && (ENV === 'production')){
serviceWorkerRegistration(); serviceWorkerRegistration();
} }

View File

@ -2,18 +2,18 @@
import { legacy_createStore as createStore} from 'redux'; //, applyMiddleware import { legacy_createStore as createStore} from 'redux'; //, applyMiddleware
// import { Provider } from 'react-redux'; // import { Provider } from 'react-redux';
import { composeWithDevTools as composeWithDevToolsWeb } from 'redux-devtools-extension'; import { composeWithDevTools as composeWithDevToolsWeb } from 'redux-devtools-extension';
import config from '../../config'; import { config } from '../../config';
import reducer, { IInitialState } from './reducers'; import reducer, { IInitialState } from './reducers';
const { env } = config; const { ENV } = config;
const composeEnhancers = composeWithDevToolsWeb({ const composeEnhancers = composeWithDevToolsWeb({
// Specify here name, actionsBlacklist, actionsCreators and other options // Specify here name, actionsBlacklist, actionsCreators and other options
}); });
const setStore = ({ initialState }: { initialState: IInitialState | undefined }) => { const setStore = ({ initialState }: { initialState: IInitialState | undefined }) => {
const store = env === 'development' ? createStore( const store = ENV === 'development' ? createStore(
reducer, reducer,
initialState, initialState,
composeEnhancers(), composeEnhancers(),

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,7 +24,7 @@ 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 } = config;
const routesUrls = routes.map( route => route.path); const routesUrls = routes.map( route => route.path);
@ -32,7 +32,7 @@ const app = express();
// @ts-ignore:next-line // @ts-ignore:next-line
const compiler = webpack(webpackConfig); const compiler = webpack(webpackConfig);
if(env === 'development'){ if(ENV === 'development'){
const serverConfig = { const serverConfig = {
serverSideRender: true, serverSideRender: true,
publicPath: webpackConfig.output?.publicPath, publicPath: webpackConfig.output?.publicPath,
@ -122,6 +122,6 @@ 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 {
@ -18,8 +18,8 @@ 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
}catch(err){ }catch(err){
// console.error(err); // console.error(err);

View File

@ -1,5 +1,6 @@
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import webpackNodeExternals from 'webpack-node-externals'; import webpackNodeExternals from 'webpack-node-externals';
import WebpackShellPluginNext from 'webpack-shell-plugin-next';
import path from 'path'; import path from 'path';
import { Configuration } from 'webpack'; import { Configuration } from 'webpack';
const ROOT_DIR = path.resolve(__dirname); const ROOT_DIR = path.resolve(__dirname);
@ -57,7 +58,7 @@ const config: Configuration = {
test: fontsAndImagesExtensions, test: fontsAndImagesExtensions,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '/assets/media/[name].[ext]', name: '/assets/[name].[ext]',
emitFile: false, emitFile: false,
}, },
}, },
@ -82,6 +83,13 @@ const config: Configuration = {
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'assets/app.css', filename: 'assets/app.css',
}), }),
new WebpackShellPluginNext({
onBuildEnd: {
scripts: ['node build/server.js'],
blocking: false,
parallel: true
}
})
], ],
}; };

View File

@ -1,24 +1,43 @@
import path from 'path'; import path from 'path';
import * as dotenv from 'dotenv'; import fs from 'fs';
import { deFaultValues } 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';
import ESLintPlugin from 'eslint-webpack-plugin'; import ESLintPlugin from 'eslint-webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin'; import CopyPlugin from 'copy-webpack-plugin';
const dotEnvToParse = dotenv.config();
const ROOT_DIR = path.resolve(__dirname); const ROOT_DIR = path.resolve(__dirname);
const resolvePath = (...args: string[]) => path.resolve(ROOT_DIR, ...args); const resolvePath = (...args: string[]) => path.resolve(ROOT_DIR, ...args);
const BUILD_DIR = resolvePath('build'); const BUILD_DIR = resolvePath('build');
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const copyPatterns = [
{
from: `${ROOT_DIR}/../public/manifest.json`, to: '',
},
{
from: `${ROOT_DIR}/../public/favicon.ico`, to: '',
},
{
from: `${ROOT_DIR}/../public/logo192.png`, to: '',
},
{
from: `${ROOT_DIR}/../public/logo512.png`, to: '',
},
]
if(fs.existsSync(`${ROOT_DIR}/../public/img`)){
copyPatterns.push({
from: `${ROOT_DIR}/../public/img`, to: 'assets/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=/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: PUBLIC_URL, publicPath: deFaultValues.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
@ -52,7 +71,7 @@ const config: Configuration = {
test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/, test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: 'assets/media/[name].[ext]', name: 'assets/[name].[ext]',
}, },
}, },
{ {
@ -72,25 +91,11 @@ const config: Configuration = {
filename: 'assets/[name].css', filename: 'assets/[name].css',
}), }),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.DefinePlugin({ new webpack.EnvironmentPlugin({
'process.env': JSON.stringify(dotEnvToParse.parsed), ...deFaultValues,
'process.env.PUBLIC_URL': JSON.stringify(PUBLIC_URL),
}), }),
new CopyPlugin({ new CopyPlugin({
patterns: [ patterns: copyPatterns
{
from: `${ROOT_DIR}/../public/manifest.json`, to: '',
},
{
from: `${ROOT_DIR}/../public/favicon.ico`, to: '',
},
{
from: `${ROOT_DIR}/../public/logo192.png`, to: '',
},
{
from: `${ROOT_DIR}/../public/logo512.png`, to: '',
},
]
}), }),
], ],
optimization: { optimization: {

View File

@ -1,5 +1,6 @@
import path from 'path'; import path from 'path';
import * as dotenv from 'dotenv'; import fs from 'fs';
import { deFaultValues } 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';
@ -10,14 +11,33 @@ import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin'; import ESLintPlugin from 'eslint-webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin'; import CopyPlugin from 'copy-webpack-plugin';
const dotEnvToParse = dotenv.config();
const ROOT_DIR = path.resolve(__dirname); const ROOT_DIR = path.resolve(__dirname);
const resolvePath = (...args) => path.resolve(ROOT_DIR, ...args); const resolvePath = (...args) => path.resolve(ROOT_DIR, ...args);
const BUILD_DIR = resolvePath('build'); const BUILD_DIR = resolvePath('build');
const { InjectManifest } = require('workbox-webpack-plugin'); const { InjectManifest } = require('workbox-webpack-plugin');
const nodeExternals = require('webpack-node-externals'); const nodeExternals = require('webpack-node-externals');
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const copyPatterns = [
{
from: `${ROOT_DIR}/public/manifest.json`, to: '',
},
{
from: `${ROOT_DIR}/public/favicon.ico`, to: '',
},
{
from: `${ROOT_DIR}/public/logo192.png`, to: '',
},
{
from: `${ROOT_DIR}/public/logo512.png`, to: '',
},
]
if(fs.existsSync(`${ROOT_DIR}/public/img`)){
copyPatterns.push({
from: `${ROOT_DIR}/public/img`, to: 'assets/img',
})
}
const frontendConfig = { const frontendConfig = {
entry: { entry: {
@ -26,7 +46,7 @@ const frontendConfig = {
output: { output: {
path: BUILD_DIR, path: BUILD_DIR,
filename: 'assets/app-[name]-[fullhash].js', filename: 'assets/app-[name]-[fullhash].js',
publicPath: PUBLIC_URL, publicPath: deFaultValues.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
@ -57,7 +77,7 @@ const frontendConfig = {
test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/, test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: 'assets/media/[name].[ext]', name: 'assets/[name].[ext]',
}, },
}, },
{ {
@ -88,25 +108,11 @@ const frontendConfig = {
], ],
}), }),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.DefinePlugin({ new webpack.EnvironmentPlugin({
'process.env': JSON.stringify(dotEnvToParse.parsed), ...deFaultValues,
'process.env.PUBLIC_URL': JSON.stringify(PUBLIC_URL),
}), }),
new CopyPlugin({ new CopyPlugin({
patterns: [ patterns: copyPatterns
{
from: `${ROOT_DIR}/public/manifest.json`, to: '',
},
{
from: `${ROOT_DIR}/public/favicon.ico`, to: '',
},
{
from: `${ROOT_DIR}/public/logo192.png`, to: '',
},
{
from: `${ROOT_DIR}/public/logo512.png`, to: '',
},
]
}), }),
new InjectManifest({ new InjectManifest({
swSrc: './service-worker.ts', swSrc: './service-worker.ts',
@ -148,7 +154,7 @@ 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: PUBLIC_URL, publicPath: deFaultValues.PUBLIC_URL,
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
@ -179,7 +185,7 @@ const serverConfig = {
test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/, test: /\.(png|jpg|jpeg|gif|svg|ico|mp4|avi|ttf|otf|eot|woff|woff2|pdf)$/,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: 'assets/media/[name].[ext]', name: 'assets/[name].[ext]',
}, },
}, },
{ {
@ -205,9 +211,8 @@ const serverConfig = {
}), }),
new CleanWebpackPlugin(), new CleanWebpackPlugin(),
new ESLintPlugin(), new ESLintPlugin(),
new webpack.DefinePlugin({ new webpack.EnvironmentPlugin({
'process.env': JSON.stringify(dotEnvToParse.parsed), ...deFaultValues,
'process.env.PUBLIC_URL': JSON.stringify(PUBLIC_URL),
}), }),
new InjectManifest({ new InjectManifest({
swSrc: './service-worker.ts', swSrc: './service-worker.ts',