Compare commits

..

No commits in common. "master" and "0.0.1" have entirely different histories.

30 changed files with 103 additions and 17499 deletions

View File

@ -2,7 +2,9 @@
ENV= #Default production
#App Port
PORT= #Default 80
#Host
HOST= #Default localhost
#PUBLIC URL
PUBLIC_URL= #Default 'auto'
#Prefix URL
PREFIX_URL= #Default ''
#ONLY EXACT PATH
ONLY_EXACT_PATH= #Default false

View File

@ -1,40 +0,0 @@
name: NPM testing and publish package
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm test
cypress-run-component:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
uses: cypress-io/github-action@v5 # use the explicit version number
with:
component: true
publish-npm:
needs: [ build, cypress-run-component ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm publish --access=public
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

View File

@ -1,44 +0,0 @@
name: Testing package
on:
pull_request:
branches: ['*']
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm test
cypress-run-component:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
uses: cypress-io/github-action@v5 # use the explicit version number
with:
component: true
test-build-package:
needs: [ test, cypress-run-component ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm run build:frontend

3
.gitignore vendored
View File

@ -7,7 +7,6 @@ build
src/server/main
src/server/react-server
src/server/web/dist
src/server/web/conversion
src/server/web/getstate
src/server/web/utils
#cypress
cypress/videos

View File

@ -1,6 +1,6 @@
# Create React SSR
This project aims to have a starter kit for creating a new React app with Server Side Rendering with a backend in go and tools that generally go along with it.
This project aims to have a starter kit for creating a new React app with Server Side Rendering and tools that generally go along with it.
It is not a project like create-react-app, create-react-app is used as a starter kit that handles all your scripts underneath, this is a project for developers who want more control over their application.
@ -8,15 +8,15 @@ Tech(Library or Framework) | Version |
--- | --- |
React (Render Library) | 18.2.0
Redux (Global State Management) | 4.2.1
React Router DOM (Routing) | 6.17.0
Jest (Testing) | 29.7.0
Cypress (E2E Testing) | 13.3.1
React Router DOM (Routing) | 6.15.0
Jest (Testing) | 29.6.4
Cypress (E2E Testing) | 13.1.0
Typescript | 5.2.2
## Setup
To create a new project run in the terminal:
```
npx @aleleba/create-react-go-ssr app-name
npx @aleleba/create-react-ssr app-name
```
Then run:
```
@ -29,33 +29,34 @@ This is an exaple of config.
ENV= #Default production
#App Port
PORT= #Default 80
#Host
HOST= #Default localhost
#PUBLIC URL
PUBLIC_URL= #Default 'auto'
#Prefix URL
PREFIX_URL= #Default ''
#ONLY EXACT PATH
ONLY_EXACT_PATH= #Default false
```
The default environment is production and the app port defauld is 80.
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
In the terminal run:
```
npm run start-frontend:dev
npm run start-server:dev
npm run start:dev
```
The ENV enviroment variable should be "development" and choose the port of your preference with the enviroment variable PORT.
You will find the root component on:
```
src/frontend/components/App.tsx
scr/frontend/components/App.tsx
```
You will find the Initial Component on:
```
src/frontend/components/InitialComponent.tsx
scr/frontend/components/InitialComponent.tsx
```
The manage of the routes you should find on:
```
src/routes
scr/routes
```
It is using "useRoutes" hook for working, more information for this here: (https://reactrouter.com/docs/en/v6/api#useroutes)

View File

@ -1,110 +0,0 @@
#!/usr/bin/env node
const { execSync } = require('child_process');
var fs = require('fs');
const isWin = process.platform === 'win32';
const runCommand = command => {
try{
execSync(`${command}`, {stdio: 'inherit'});
} catch (e) {
console.error(`Failed to execute ${command}`, e);
return false;
}
return true;
};
const runCommandWithOutput = command => {
try{
return execSync(`${command}`);
} catch (e) {
console.error(`Failed to execute ${command}`, e);
return false;
}
};
const replaceTextOnFile = ({
file,
textToBeReplaced,
textReplace,
arrOfObjectsBeReplaced
}) => {
let data;
try{
data = fs.readFileSync(file, 'utf8');
} catch (e) {
console.error(`Failed to read file ${file}`, e);
return false;
}
let result;
if(arrOfObjectsBeReplaced){
arrOfObjectsBeReplaced.forEach( obj => {
if(result){
result = result.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' ');
}else{
result = data.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' ');
}
});
}else{
result = data.replace(textToBeReplaced, textReplace).replace(/^\s*[\r\n]/gm, ' ');
}
try{
console.log('text changed');
fs.writeFileSync(file, result, 'utf8');
} catch (e) {
console.error(`Failed to read file ${file}`, e);
return false;
}
};
const repoName = process.argv[2];
const gitCheckoutCommand = `git clone --depth 1 https://github.com/aleleba/create-react-go-ssr ${repoName}`;
console.log(`Cloning the repository with name ${repoName}`);
const checkedOut = runCommand(gitCheckoutCommand);
if(!checkedOut) process.exit(-1);
const actualVersion = runCommandWithOutput(`cd ${repoName} && node -p "require('./package.json').version"`).toString().trim();
const installDepsCommand = `cd ${repoName} && npm install`;
const cleanGitHistoryCommand = `cd ${repoName} && rm -rf .git && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"`;
const cleanGitHistoryCommandWindows = `cd ${repoName} && rmdir .git /s /q && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"`;
const deleteFoldersCommand = `cd ${repoName} && rm -rf .github && rm -rf bin`;
const deleteFoldersCommandWindows = `cd ${repoName} && rmdir .github /s /q && rmdir bin /s /q`;
console.log(`Installing dependencies for ${repoName}`);
const installedDeps = runCommand(installDepsCommand);
if(!installedDeps) process.exit(-1);
console.log(`Replacing Json data for ${repoName}`);
replaceTextOnFile({
file: `./${repoName}/package.json`,
arrOfObjectsBeReplaced: [
{
textToBeReplaced: '"bin": "./bin/cli.js",',
textReplace: ''
},
{
textToBeReplaced: `"version": "${actualVersion}",`,
textReplace: '"version": "0.0.1",'
},
{
textToBeReplaced: '"name": "@aleleba/create-react-go-ssr",',
textReplace: `"name": "${repoName}",`
}
]
});
console.log(`Cleaning History of Git for ${repoName}`);
const cleanGitHistory = isWin ? runCommand(cleanGitHistoryCommandWindows) : runCommand(cleanGitHistoryCommand);
if(!cleanGitHistory) process.exit(-1);
console.log('Congratulations! You are ready. Follow the following commands to start');
console.log(`cd ${repoName}`);
console.log('Create a .env file with ENV=development(default: production), PORT=3000 (default: 80), HOST=domain.com (default: localhost), PREFIX_URL= (default: is empty)');
console.log('Then you can run: npm start-frontend:dev');
console.log('Then you can run: npm start-server:dev');
const deleteFolders = isWin ? runCommand(deleteFoldersCommandWindows) : runCommand(deleteFoldersCommand);
if(!deleteFolders) process.exit(-1);

View File

@ -4,7 +4,6 @@ export const deFaultValues = {
PUBLIC_URL: 'auto',
PREFIX_URL: '',
ONLY_EXACT_PATH: false,
HOST: 'localhost',
};
export const config = {
@ -13,7 +12,6 @@ export const config = {
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,
HOST: process.env.HOST ? process.env.HOST : deFaultValues.HOST,
};
export default config;

View File

@ -1,20 +0,0 @@
describe('Initial Component Tests', () => {
it('Will show the Initial Component page.', () => {
cy.visit('/');
cy.get('a').contains('Other Component');
});
it('Will Redirect to Other Component page.', () => {
cy.visit('/');
cy.get('a').contains('Other Component').click();
cy.get('a').contains('Initial Component');
});
it('Will show the Other Component page.', () => {
cy.visit('/other-component');
cy.get('a').contains('Initial Component');
});
it('Will Redirect to Initial Component page.', () => {
cy.visit('/other-component');
cy.get('a').contains('Initial Component').click();
cy.get('a').contains('Other Component');
});
});

View File

@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -1,37 +0,0 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<base href="/__cypress/src/" />
<title>Components App</title>
</head>
<body>
<div data-cy-root></div>
</body>
</html>

View File

@ -1,42 +0,0 @@
// ***********************************************************
// This example support/component.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
//Importing global styles
import '../../src/frontend/styles/global.scss';
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
import { mount } from 'cypress/react18';
// Augment the Cypress namespace to include type definitions for
// your custom command.
// Alternatively, can be defined in cypress/support/component.d.ts
// with a <reference path="./component" /> at the top of your spec.
declare global {
namespace Cypress {
interface Chainable {
mount: typeof mount
}
}
}
Cypress.Commands.add('mount', mount);
// Example use:
// cy.mount(<MyComponent />)

View File

@ -1,20 +0,0 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')

16890
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,15 @@
{
"name": "@aleleba/create-react-go-ssr",
"version": "1.0.4",
"description": "Starter Kit of server side render of react with backend in go",
"version": "0.0.1",
"description": "Starter Kit of server side render of react",
"bin": "./bin/cli.js",
"main": "src/server/index",
"scripts": {
"start": "cd build/server && ./react-server",
"start-frontend:dev": "webpack watch --config webpack.config.ts",
"start-server:dev": "cd src/server && go run main.go",
"build": "webpack --config webpack.config.ts && cd src/server && go build && mkdir ../../build && cp -r ./ ../../build/server && cp -r ../routes ../../build/routes && rm -rf ./react-server",
"build:frontend": "webpack --config webpack.config.ts",
"start": "webpack watch --config webpack.config.ts",
"buildTsxToString": "webpack --config webpack.config.convert.ts",
"start:dev": "rm -rf build && webpack --mode=development --config webpack.config.dev.server.ts",
"start:dev-win": "(if exist build rmdir /s /Q build) && webpack --mode=development --config webpack.config.dev.server.ts",
"build": "webpack-cli --config webpack.config.ts",
"lint": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx",
"lint:fix": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx --fix",
"test": "jest",
@ -25,8 +26,6 @@
"keywords": [
"create react app",
"react",
"go",
"golang",
"ssr",
"typescript",
"redux"
@ -34,9 +33,9 @@
"author": "Alejandro Lembke Barrientos",
"license": "MIT",
"bugs": {
"url": "https://github.com/aleleba/create-react-go-ssr/issues"
"url": "https://github.com/aleleba/create-react-ssr/issues"
},
"homepage": "https://github.com/aleleba/create-react-go-ssr#readme",
"homepage": "https://github.com/aleleba/create-react-ssr#readme",
"dependencies": {
"@babel/register": "^7.22.15",
"dotenv": "^16.3.1",
@ -46,11 +45,11 @@
"ignore-styles": "^5.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.3",
"react-router-dom": "^6.17.0",
"react-redux": "^8.1.2",
"react-router-dom": "^6.15.0",
"react-router-hash-link": "^2.4.3",
"redux": "^4.2.1",
"webpack": "^5.89.0",
"webpack": "^5.88.2",
"webpack-manifest-plugin": "^5.0.0",
"workbox-background-sync": "^7.0.0",
"workbox-broadcast-update": "^7.0.0",
@ -66,45 +65,45 @@
"workbox-streams": "^7.0.0"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/core": "^7.22.17",
"@babel/preset-env": "^7.22.15",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.23.2",
"@babel/preset-typescript": "^7.22.15",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@redux-devtools/extension": "^3.2.5",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/jest-dom": "^6.1.3",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.1",
"@types/jest": "^29.5.5",
"@types/node": "^20.8.6",
"@types/react": "^18.2.28",
"@types/react-dom": "^18.2.13",
"@types/webpack": "^5.28.3",
"@types/webpack-hot-middleware": "^2.25.7",
"@types/webpack-node-externals": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
"babel-jest": "^29.7.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^29.5.4",
"@types/node": "^20.6.0",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/webpack": "^5.28.2",
"@types/webpack-hot-middleware": "^2.25.6",
"@types/webpack-node-externals": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"babel-jest": "^29.6.4",
"babel-loader": "^9.1.3",
"clean-webpack-plugin": "^4.0.0",
"compression-webpack-plugin": "^10.0.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"cypress": "^13.3.1",
"eslint": "^8.51.0",
"cypress": "^13.1.0",
"eslint": "^8.49.0",
"eslint-plugin-react": "^7.33.2",
"eslint-webpack-plugin": "^4.0.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.3",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest": "^29.6.4",
"jest-environment-jsdom": "^29.6.4",
"jest-fetch-mock": "^3.0.3",
"mini-css-extract-plugin": "^2.7.6",
"react-refresh": "^0.14.0",
"resolve-ts-aliases": "^1.0.1",
"sass": "^1.69.3",
"sass": "^1.66.1",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"terser-webpack-plugin": "^5.3.9",

View File

@ -1,27 +0,0 @@
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import initialStateReducer from '../frontend/reducers/initialState';
import setStore from '../frontend/setStore';
export const ProviderMock = ({ children, initialState }: { children: unknown, initialState?: unknown}) => {
let initialStateMock = initialStateReducer;
if(initialState !== undefined){
initialStateMock = initialState as unknown as typeof initialStateReducer;
}
const history = createMemoryHistory();
const store = setStore({ initialState: initialStateMock });
return(
<Provider store={store}>
<Router location={history.location} navigator={history}>
{children as JSX.Element}
</Router>
</Provider>
);
};
export default ProviderMock;

View File

@ -1,2 +0,0 @@
export const fileMock = '';
module.exports = fileMock;

View File

@ -1 +0,0 @@
export * from './ProviderMock';

View File

@ -1,19 +1,15 @@
import React, { useEffect } from 'react';
import PrincipalRoutes from './PrincipalRoutes';
import { config } from '../../../config';
const App = () => {
const { PREFIX_URL } = config;
if(config.ENV === 'development') {
useEffect(() => {
const ws = new WebSocket(`wss://${config.HOST}${PREFIX_URL}/ws`);
const ws = new WebSocket('wss://xs70kvlc-3000.use.devtunnels.ms/ws');
ws.onmessage = (event) => {
if (event.data === 'reload') {
window.location.reload();
}
};
}, []);
}
return <PrincipalRoutes />;
};

View File

@ -1,15 +1,11 @@
import React from 'react';
import './InitialComponent.scss';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
const InitialComponent = ({ hello }: { hello: string }) => {
return(
const InitialComponent = () => (
<div className="App">
<header className="App-header">
<img src="assets/img/logo.svg" className="App-logo" alt="logo" />
<p>This is the text from the store of redux: <strong>{hello}</strong></p>
<p>
Edit <code>src/frontend/InitialComponent.jsx</code> and save to reload.
</p>
@ -25,12 +21,5 @@ const InitialComponent = ({ hello }: { hello: string }) => {
</header>
</div>
);
};
const mapStateToProps = (state) => {
return {
hello: state.testReducer.hello
};
};
export default connect(mapStateToProps)(InitialComponent);
export default InitialComponent;

View File

@ -1,23 +1,15 @@
import React from 'react';
//Redux
import { Provider } from 'react-redux';
import setStore from '../setStore';
import initialState from '../reducers/initialState';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom/server';
import App from '../components/App';
const url = process.argv[2];
const store = setStore({ initialState });
const render = () => {
return renderToString(
<Provider store={store}>
<StaticRouter location={`${url}`} >
<App />
</StaticRouter>
</Provider>
);
};

View File

@ -1,5 +0,0 @@
import setStore from '../setStore';
import initialState from '../reducers/initialState';
const store = setStore({ initialState });
const preloadedState = store.getState();
console.log(preloadedState);

View File

@ -10,7 +10,7 @@ import { config } from '../../config';
import './styles/global.scss';
import App from './components/App';
import serviceWorkerRegistration from '../../serviceWorkerRegistration';
// import serviceWorkerRegistration from '../../serviceWorkerRegistration';
declare global {
interface Window {
@ -72,9 +72,9 @@ ENV === 'production' && hydrateRoot(container,
</Provider>
); */
if((ENV) && (ENV === 'production')){
/* if((ENV) && (ENV === 'production')){
serviceWorkerRegistration();
}
} */
/* if(module.hot){
module.hot.accept();

View File

@ -1,3 +1,2 @@
import { IInitialState } from './';
const initialState: IInitialState = {};
const initialState = {};
export default initialState;

View File

@ -6,9 +6,8 @@ import (
)
func LoadEnv() {
err := godotenv.Load("../../.env")
err := godotenv.Load(".env")
if err != nil {
// log.Fatal("Error loading .env file")
log.Println("Is no .env file")
log.Fatal("Error loading .env file")
}
}

View File

@ -21,10 +21,6 @@ func main() {
//Getting the port from the environment
port := os.Getenv("PORT")
if(port == "") {
port = "80"
}
paths := utils.GetRoutes()
e := echo.New()

View File

@ -1,37 +0,0 @@
package utils
import (
"fmt"
"os/exec"
)
func GetPreloadedState() string {
// Set the path to the jsxToString.js file
jsFilePath := "./web/getstate/getPreloadedState.js"
// Create the command to run Node.js with the jsxToString.js file
cmd := exec.Command("node", jsFilePath)
// Get a pipe to the standard input of the Node.js process
stdin, err := cmd.StdinPipe()
if err != nil {
fmt.Println(err)
return ""
}
// Write the URL parameter to the standard input of the Node.js process
//fmt.Fprintf(stdin, "%s\n", url)
// Close the standard input pipe
stdin.Close()
// Get the output and error of the Node.js process
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(err)
return string(output)
}
// Return the output of the Node.js process
return string(output)
}

View File

@ -7,7 +7,7 @@ import (
func JsxToString(url string) string {
// Set the path to the jsxToString.js file
jsFilePath := "./web/conversion/tsxToString.js"
jsFilePath := "./web/utils/tsxToString.js"
// Create the command to run Node.js with the jsxToString.js file
cmd := exec.Command("node", jsFilePath, url)

View File

@ -32,7 +32,6 @@ func RegisterHandlers(e *echo.Echo, paths []string) {
//return c.File(filePath)
url := c.Request().URL.String()
component := utils.JsxToString(url)
preloadedState := utils.GetPreloadedState();
html := `<!DOCTYPE html>
<html lang="es">
<head>
@ -48,9 +47,9 @@ func RegisterHandlers(e *echo.Echo, paths []string) {
</head>
<body>
<div id="app">`+ component +`</div>
<script>
window.__PRELOADED_STATE__ = JSON.stringify(`+ preloadedState+`).replace(/</g, '\\u003c')
</script>
<!-- <script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script> -->
<script src="assets/app-frontend.js" type="text/javascript"></script>
<script src="assets/vendor-vendors.js" type="text/javascript"></script>
</body>

View File

@ -1,6 +1,5 @@
import path from 'path';
import fs from 'fs';
import dotenv from 'dotenv'
import { config as envConfig } from './config';
import webpack from 'webpack';
import CompressionWebpackPlugin from 'compression-webpack-plugin';
@ -16,9 +15,8 @@ import { resolveTsAliases } from 'resolve-ts-aliases';
const ROOT_DIR = path.resolve(__dirname);
const resolvePath = (...args) => path.resolve(ROOT_DIR, ...args);
const BUILD_DIR = resolvePath(__dirname + '/src/server/web/dist');
const BUILD_DIR_CONVERSION = resolvePath(__dirname + '/src/server/web/conversion');
const BUILD_DIR_GET_STATE = resolvePath(__dirname + '/src/server/web/getstate');
const { InjectManifest } = require('workbox-webpack-plugin');
const BUILD_DIR_CONVERSION = resolvePath(__dirname + '/src/server/web/utils');
//const { InjectManifest } = require('workbox-webpack-plugin');
//const nodeExternals = require('webpack-node-externals');
const alias = resolveTsAliases(path.resolve('tsconfig.json'));
@ -44,17 +42,6 @@ if(fs.existsSync(`${ROOT_DIR}/public/img`)){
});
}
// call dotenv and it will return an Object with a parsed key
const env = dotenv.config().parsed;
// reduce it to a nice object, the same as before
const envKeys = Object.keys(dotenv.config({}).parsed || {}).reduce((prev, next) => {
if (dotenv.config().parsed && env && env[next]) {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
}
return prev;
}, {});
const configReact = {
entry: {
frontend: `${ROOT_DIR}/src/frontend/index.tsx`,
@ -125,16 +112,15 @@ const configReact = {
}),
new ESLintPlugin(),
new webpack.EnvironmentPlugin({
envKeys,
...envConfig,
}),
new CopyPlugin({
patterns: copyPatterns
}),
new InjectManifest({
/*new InjectManifest({
swSrc: './service-worker.ts',
swDest: 'service-worker.js',
}),
}),*/
],
optimization: {
minimize: true,
@ -214,6 +200,9 @@ const configTSXConversion = {
],
}),
new ESLintPlugin(),
new webpack.EnvironmentPlugin({
...envConfig,
}),
],
optimization: {
minimize: true,
@ -224,65 +213,4 @@ const configTSXConversion = {
},
};
const configGetPreloadedState = {
entry: {
getPreloadedState: `${ROOT_DIR}/src/frontend/getPreloadedState/getPreloadedState.ts`,
},
output: {
path: BUILD_DIR_GET_STATE,
//filename: 'assets/app-[name]-[fullhash].js',
filename: '[name].js',
publicPath: envConfig.PUBLIC_URL,
globalObject: 'this',
},
resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias
},
mode: 'production',
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new CompressionWebpackPlugin({
test: /\.(js|css)$/,
filename: '[path][base].gz',
}),
new MiniCssExtractPlugin({
//filename: 'assets/[name]-[fullhash].css',
filename: '[name].css',
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*',
'!server/**',
],
}),
new ESLintPlugin(),
],
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin(),
],
},
};
export default [configReact, configTSXConversion, configGetPreloadedState];
export default [configReact, configTSXConversion];