Skip to content

Commit e41ca43

Browse files
authored
Merge pull request #31 from Pachon10/master
#20 Example about how to use webpack proxy
2 parents 3815345 + 0f6dc57 commit e41ca43

22 files changed

+640
-0
lines changed
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"presets": [
3+
"@babel/preset-env",
4+
"@babel/preset-react",
5+
"@babel/preset-typescript"
6+
]
7+
}
+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# 17 proxy
2+
3+
In this demo we are going to configure Webpack proxy, proxying some URLs can be useful when you have a separate API backend development server and you want to send API requests on the same domain.
4+
5+
We will start from sample _16-bundle-analyzer.
6+
7+
Summary steps:
8+
9+
- Configure _webpack.config_ to send requests from the app's domain to the API.
10+
- Modify webpack.dev.js.
11+
- Modify webpack.prod.js.
12+
- Create script apiTest.tsx.
13+
- Modify index.tsx
14+
15+
# Steps to build it
16+
17+
## Prerequisites
18+
19+
Prerequisites, you will need to have nodejs installed in your computer. If you want to follow this step guides you will need to take as starting point sample _16-bundle-analyzer.
20+
21+
## Steps
22+
23+
- `npm install` to install previous sample packages:
24+
25+
```
26+
npm install
27+
```
28+
29+
- Now is the time to modify the performance configuration file.
30+
31+
_./webpack.common.js_
32+
33+
```diff
34+
module.exports = {
35+
....
36+
plugins: [
37+
new CleanWebpackPlugin(),
38+
//Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin
39+
new HtmlWebpackPlugin({
40+
filename: "index.html", //Name of file in ./dist/
41+
template: "index.html", //Name of template in ./src
42+
}),
43+
new MiniCssExtractPlugin({
44+
filename: "[name].css",
45+
chunkFilename: "[id].css",
46+
}),
47+
],
48+
+ devServer: {
49+
+ proxy: {
50+
+ "/api": {
51+
+ //The origin of the host header is kept when proxying by default: if true to override this behaviour.
52+
+ //Use when is name-based hosted sites.
53+
+ "changeOrigin": true,
54+
+ //If you don't want /api to be passed along, we need to rewrite the path:
55+
+ pathRewrite: { "^/api": "" },
56+
+ // If you want filter the request type
57+
+ bypass: function(req, res, proxyOptions) {
58+
+ if(req.method != 'GET') return false;
59+
+ }
60+
+ },
61+
+ "/get": {
62+
+ //The origin of the host header is kept when proxying by default: if true to override this behaviour.
63+
+ //Use when is name-based hosted sites.
64+
+ "changeOrigin": true,
65+
+ //If you don't want /api/get to be passed along, we need to rewrite the path:
66+
+ pathRewrite: { "^/api/get": "" },
67+
+ // If you want filter the request type
68+
+ bypass: function(req, res, proxyOptions) {
69+
+ if(req.method != 'GET') return false;
70+
+ }
71+
+ }
72+
+ }
73+
+ }
74+
};
75+
```
76+
77+
- Now modifiy _webpack.dev.js_
78+
79+
```diff
80+
module.exports = merge(common, {
81+
mode: "development",
82+
devtool: "inline-source-map",
83+
devServer: {
84+
stats: "errors-only",
85+
},
86+
plugins: [
87+
new Dotenv({
88+
path: "./dev.env",
89+
}),
90+
],
91+
+ devServer: {
92+
+ proxy: {
93+
+ "/api": {
94+
+ target: "https://httpbin.org/",
95+
+ },
96+
+ "/get": {
97+
+ target: "https://httpbin.org/",
98+
+ }
99+
+ }
100+
+ },
101+
});
102+
```
103+
104+
- Now modifiy _webpack.dev.js_
105+
```diff
106+
module.exports = merge(common, {
107+
mode: "development",
108+
devtool: "inline-source-map",
109+
devServer: {
110+
stats: "errors-only",
111+
},
112+
plugins: [
113+
new Dotenv({
114+
path: "./dev.env",
115+
}),
116+
],
117+
+ devServer: {
118+
+ proxy: {
119+
+ "/api": {
120+
+ target: "https://myApi.com",
121+
+ },
122+
+ "/get": {
123+
+ target: "https://myApi.com",
124+
+ }
125+
+ }
126+
+ },
127+
});
128+
```
129+
130+
- Now create a new file _apiTest.tsx_
131+
132+
```javascript
133+
import React from "react";
134+
const reqGet = (() => {
135+
let status = "pending";
136+
let result;
137+
const resultData = fetch("api/get")
138+
.then(function (response) {
139+
return response.json();
140+
})
141+
.then(function (data) {
142+
status = "success";
143+
console.log(data);
144+
result = data;
145+
})
146+
.catch(error => {
147+
status = "error";
148+
result = `${status} ${error}`;
149+
});
150+
151+
return {
152+
Request() {
153+
if (status === "pending") {
154+
console.log(status);
155+
throw resultData;
156+
} else if (status === "error") {
157+
console.log(status);
158+
return result;
159+
} else if (status === "success") {
160+
console.log(status);
161+
return result;
162+
}
163+
}
164+
}
165+
})()
166+
167+
function getListObject(obj) {
168+
return (
169+
<ul>
170+
{Object.keys(obj).map((keyOb) =>
171+
(<li>
172+
{keyOb}:&nbsp;
173+
{typeof obj[keyOb] === "object" ?
174+
getListObject(obj[keyOb]) :
175+
obj[keyOb]}
176+
</li>))}
177+
</ul>
178+
)
179+
}
180+
181+
export const RequestGet = () => {
182+
let obj = reqGet.Request();
183+
return (<div>
184+
<h5>Result API http://localhost:8080/api/get: </h5>
185+
{typeof obj === "object" ? getListObject(obj) : obj}
186+
</div>);
187+
}
188+
```
189+
190+
Finally, we need to update _index.tsx_:
191+
192+
```diff
193+
import React, { Suspense } from "react";
194+
import ReactDOM from "react-dom";
195+
++ import { RequestGet } from "./apiTest";
196+
import { AverageComponent } from "./averageComponent";
197+
import { TotalScoreComponent } from './totalScoreComponent';
198+
199+
ReactDOM.render(
200+
<div>
201+
<h1>Hello from React DOM</h1>
202+
<AverageComponent />
203+
<TotalScoreComponent />
204+
++ <Suspense fallback={<h1>Loading ...</h1>}>
205+
++ <RequestGet />
206+
++ </Suspense>
207+
</div>,
208+
document.getElementById("root")
209+
);
210+
```
211+
212+
- Now we execute the command `npm start`
213+
214+
```bash
215+
npm start
216+
```
217+
218+
# About Basefactor + Lemoncode
219+
220+
We are an innovating team of Javascript experts, passionate about turning your ideas into robust products.
221+
222+
[Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services.
223+
224+
[Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services.
225+
226+
For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
API_BASE=https://httpbin.org/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"name": "02-boiler-plate",
3+
"version": "1.0.0",
4+
"description": "In this sample we are going to setup a web project that can be easily managed by webpack.",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "run-p -l type-check:watch start:dev",
8+
"type-check": "tsc --noEmit",
9+
"type-check:watch": "npm run type-check -- --watch",
10+
"start:dev": "webpack serve --mode development --config webpack.dev.js",
11+
"start:prod": "webpack serve --config webpack.prod.js",
12+
"build:dev": "rimraf dist && webpack --config webpack.dev.js",
13+
"build:prod": "rimraf dist && webpack --config webpack.prod.js",
14+
"build:perf": "rimraf dist && webpack --config webpack.perf.js"
15+
},
16+
"keywords": [],
17+
"author": "",
18+
"license": "ISC",
19+
"devDependencies": {
20+
"@babel/cli": "^7.12.1",
21+
"@babel/core": "^7.12.3",
22+
"@babel/preset-env": "^7.12.1",
23+
"@babel/preset-react": "^7.12.5",
24+
"@babel/preset-typescript": "^7.12.1",
25+
"@types/react": "^16.9.55",
26+
"@types/react-dom": "^16.9.9",
27+
"babel-loader": "^8.2.1",
28+
"clean-webpack-plugin": "^3.0.0",
29+
"css-loader": "^5.0.0",
30+
"dotenv-webpack": "^5.0.1",
31+
"html-loader": "^1.3.2",
32+
"html-webpack-plugin": "^4.5.0",
33+
"mini-css-extract-plugin": "^1.2.1",
34+
"npm-run-all": "^4.1.5",
35+
"sass": "^1.28.0",
36+
"sass-loader": "^10.0.5",
37+
"style-loader": "^2.0.0",
38+
"typescript": "^4.0.5",
39+
"webpack": "^5.4.0",
40+
"webpack-bundle-analyzer": "^3.9.0",
41+
"webpack-cli": "^4.2.0",
42+
"webpack-dev-server": "^3.11.0",
43+
"webpack-merge": "^5.3.0"
44+
},
45+
"dependencies": {
46+
"bootstrap": "^4.5.3",
47+
"react": "^17.0.1",
48+
"react-dom": "^17.0.1"
49+
}
50+
}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
API_BASE=https://myapp.api/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from "react";
2+
3+
const reqGet = (() => {
4+
let status = "pending";
5+
let result;
6+
const resultData = fetch("/api/get")
7+
.then(function (response) {
8+
return response.json();
9+
})
10+
.then(function (data) {
11+
status = "success";
12+
console.log(data);
13+
result = data;
14+
})
15+
.catch(error => {
16+
status = "error";
17+
result = `${status} ${error}`;
18+
});
19+
20+
return {
21+
Request() {
22+
if (status === "pending") {
23+
console.log(status);
24+
throw resultData;
25+
} else if (status === "error") {
26+
console.log(status);
27+
return result;
28+
} else if (status === "success") {
29+
console.log(status);
30+
return result;
31+
}
32+
}
33+
}
34+
})()
35+
36+
function getListObject(obj) {
37+
return (
38+
<ul>
39+
{Object.keys(obj).map((keyOb) =>
40+
(<li>
41+
{keyOb}:&nbsp;
42+
{typeof obj[keyOb] === "object" ?
43+
getListObject(obj[keyOb]) :
44+
obj[keyOb]}
45+
</li>))}
46+
</ul>
47+
)
48+
}
49+
50+
export const RequestGet = () => {
51+
let obj = reqGet.Request();
52+
return (<div>
53+
<h5>Result API http://localhost:8080/api/get: </h5>
54+
{typeof obj === "object" ? getListObject(obj) : obj}
55+
</div>);
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from "react";
2+
import { getAvg } from "./averageService";
3+
//const classes = require("./averageComponentStyles.scss").default;
4+
import classes from "./averageComponentStyles.scss";
5+
//import { resultBackground } from "./averageComponentStyles.scss";
6+
//import { resultBackground } from "./averageComponentStyles.css";
7+
8+
console.log(classes);
9+
10+
export const AverageComponent = () => {
11+
const [average, setAverage] = React.useState(0);
12+
13+
React.useEffect(() => {
14+
const scores = [90, 75, 60, 99, 94, 30];
15+
setAverage(getAvg(scores));
16+
}, []);
17+
18+
//className={classes["result-background"]}
19+
return (
20+
<div>
21+
<span className={classes.resultBackground}>
22+
Students average: {average}
23+
</span>
24+
<div className={`jumbotron ${classes.resultBackground}`}>
25+
<h1>Jumbotron students average: {average}</h1>
26+
</div>
27+
</div>
28+
);
29+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
$background: teal;
2+
$jumbotronBackground: darkseagreen;
3+
4+
.result-background {
5+
background-color: $background;
6+
}
7+
8+
:global(.jumbotron).result-background {
9+
background-color: $jumbotronBackground;
10+
display: block;
11+
}

0 commit comments

Comments
 (0)