Skip to content

Commit

Permalink
Lemoncode#20 Example about how to use webpack proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
Pachon10 committed Nov 19, 2020
1 parent 422d6c7 commit 0f6dc57
Show file tree
Hide file tree
Showing 22 changed files with 640 additions and 0 deletions.
7 changes: 7 additions & 0 deletions 03-bundling/01-webpack/17-proxy/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
]
}
226 changes: 226 additions & 0 deletions 03-bundling/01-webpack/17-proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# 17 proxy

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.

We will start from sample _16-bundle-analyzer.

Summary steps:

- Configure _webpack.config_ to send requests from the app's domain to the API.
- Modify webpack.dev.js.
- Modify webpack.prod.js.
- Create script apiTest.tsx.
- Modify index.tsx

# Steps to build it

## Prerequisites

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.

## Steps

- `npm install` to install previous sample packages:

```
npm install
```

- Now is the time to modify the performance configuration file.

_./webpack.common.js_

```diff
module.exports = {
....
plugins: [
new CleanWebpackPlugin(),
//Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: "index.html", //Name of file in ./dist/
template: "index.html", //Name of template in ./src
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
+ devServer: {
+ proxy: {
+ "/api": {
+ //The origin of the host header is kept when proxying by default: if true to override this behaviour.
+ //Use when is name-based hosted sites.
+ "changeOrigin": true,
+ //If you don't want /api to be passed along, we need to rewrite the path:
+ pathRewrite: { "^/api": "" },
+ // If you want filter the request type
+ bypass: function(req, res, proxyOptions) {
+ if(req.method != 'GET') return false;
+ }
+ },
+ "/get": {
+ //The origin of the host header is kept when proxying by default: if true to override this behaviour.
+ //Use when is name-based hosted sites.
+ "changeOrigin": true,
+ //If you don't want /api/get to be passed along, we need to rewrite the path:
+ pathRewrite: { "^/api/get": "" },
+ // If you want filter the request type
+ bypass: function(req, res, proxyOptions) {
+ if(req.method != 'GET') return false;
+ }
+ }
+ }
+ }
};
```

- Now modifiy _webpack.dev.js_

```diff
module.exports = merge(common, {
mode: "development",
devtool: "inline-source-map",
devServer: {
stats: "errors-only",
},
plugins: [
new Dotenv({
path: "./dev.env",
}),
],
+ devServer: {
+ proxy: {
+ "/api": {
+ target: "https://httpbin.org/",
+ },
+ "/get": {
+ target: "https://httpbin.org/",
+ }
+ }
+ },
});
```

- Now modifiy _webpack.dev.js_
```diff
module.exports = merge(common, {
mode: "development",
devtool: "inline-source-map",
devServer: {
stats: "errors-only",
},
plugins: [
new Dotenv({
path: "./dev.env",
}),
],
+ devServer: {
+ proxy: {
+ "/api": {
+ target: "https://myApi.com",
+ },
+ "/get": {
+ target: "https://myApi.com",
+ }
+ }
+ },
});
```

- Now create a new file _apiTest.tsx_

```javascript
import React from "react";
const reqGet = (() => {
let status = "pending";
let result;
const resultData = fetch("api/get")
.then(function (response) {
return response.json();
})
.then(function (data) {
status = "success";
console.log(data);
result = data;
})
.catch(error => {
status = "error";
result = `${status} ${error}`;
});

return {
Request() {
if (status === "pending") {
console.log(status);
throw resultData;
} else if (status === "error") {
console.log(status);
return result;
} else if (status === "success") {
console.log(status);
return result;
}
}
}
})()

function getListObject(obj) {
return (
<ul>
{Object.keys(obj).map((keyOb) =>
(<li>
{keyOb}:&nbsp;
{typeof obj[keyOb] === "object" ?
getListObject(obj[keyOb]) :
obj[keyOb]}
</li>))}
</ul>
)
}

export const RequestGet = () => {
let obj = reqGet.Request();
return (<div>
<h5>Result API http://localhost:8080/api/get: </h5>
{typeof obj === "object" ? getListObject(obj) : obj}
</div>);
}
```

Finally, we need to update _index.tsx_:

```diff
import React, { Suspense } from "react";
import ReactDOM from "react-dom";
++ import { RequestGet } from "./apiTest";
import { AverageComponent } from "./averageComponent";
import { TotalScoreComponent } from './totalScoreComponent';

ReactDOM.render(
<div>
<h1>Hello from React DOM</h1>
<AverageComponent />
<TotalScoreComponent />
++ <Suspense fallback={<h1>Loading ...</h1>}>
++ <RequestGet />
++ </Suspense>
</div>,
document.getElementById("root")
);
```

- Now we execute the command `npm start`

```bash
npm start
```

# About Basefactor + Lemoncode

We are an innovating team of Javascript experts, passionate about turning your ideas into robust products.

[Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services.

[Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services.

For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend
1 change: 1 addition & 0 deletions 03-bundling/01-webpack/17-proxy/dev.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
API_BASE=https://httpbin.org/
50 changes: 50 additions & 0 deletions 03-bundling/01-webpack/17-proxy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "02-boiler-plate",
"version": "1.0.0",
"description": "In this sample we are going to setup a web project that can be easily managed by webpack.",
"main": "index.js",
"scripts": {
"start": "run-p -l type-check:watch start:dev",
"type-check": "tsc --noEmit",
"type-check:watch": "npm run type-check -- --watch",
"start:dev": "webpack serve --mode development --config webpack.dev.js",
"start:prod": "webpack serve --config webpack.prod.js",
"build:dev": "rimraf dist && webpack --config webpack.dev.js",
"build:prod": "rimraf dist && webpack --config webpack.prod.js",
"build:perf": "rimraf dist && webpack --config webpack.perf.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@babel/preset-react": "^7.12.5",
"@babel/preset-typescript": "^7.12.1",
"@types/react": "^16.9.55",
"@types/react-dom": "^16.9.9",
"babel-loader": "^8.2.1",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^5.0.0",
"dotenv-webpack": "^5.0.1",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^1.2.1",
"npm-run-all": "^4.1.5",
"sass": "^1.28.0",
"sass-loader": "^10.0.5",
"style-loader": "^2.0.0",
"typescript": "^4.0.5",
"webpack": "^5.4.0",
"webpack-bundle-analyzer": "^3.9.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.3.0"
},
"dependencies": {
"bootstrap": "^4.5.3",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
1 change: 1 addition & 0 deletions 03-bundling/01-webpack/17-proxy/prod.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
API_BASE=https://myapp.api/
56 changes: 56 additions & 0 deletions 03-bundling/01-webpack/17-proxy/src/apiTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from "react";

const reqGet = (() => {
let status = "pending";
let result;
const resultData = fetch("/api/get")
.then(function (response) {
return response.json();
})
.then(function (data) {
status = "success";
console.log(data);
result = data;
})
.catch(error => {
status = "error";
result = `${status} ${error}`;
});

return {
Request() {
if (status === "pending") {
console.log(status);
throw resultData;
} else if (status === "error") {
console.log(status);
return result;
} else if (status === "success") {
console.log(status);
return result;
}
}
}
})()

function getListObject(obj) {
return (
<ul>
{Object.keys(obj).map((keyOb) =>
(<li>
{keyOb}:&nbsp;
{typeof obj[keyOb] === "object" ?
getListObject(obj[keyOb]) :
obj[keyOb]}
</li>))}
</ul>
)
}

export const RequestGet = () => {
let obj = reqGet.Request();
return (<div>
<h5>Result API http://localhost:8080/api/get: </h5>
{typeof obj === "object" ? getListObject(obj) : obj}
</div>);
}
29 changes: 29 additions & 0 deletions 03-bundling/01-webpack/17-proxy/src/averageComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { getAvg } from "./averageService";
//const classes = require("./averageComponentStyles.scss").default;
import classes from "./averageComponentStyles.scss";
//import { resultBackground } from "./averageComponentStyles.scss";
//import { resultBackground } from "./averageComponentStyles.css";

console.log(classes);

export const AverageComponent = () => {
const [average, setAverage] = React.useState(0);

React.useEffect(() => {
const scores = [90, 75, 60, 99, 94, 30];
setAverage(getAvg(scores));
}, []);

//className={classes["result-background"]}
return (
<div>
<span className={classes.resultBackground}>
Students average: {average}
</span>
<div className={`jumbotron ${classes.resultBackground}`}>
<h1>Jumbotron students average: {average}</h1>
</div>
</div>
);
};
11 changes: 11 additions & 0 deletions 03-bundling/01-webpack/17-proxy/src/averageComponentStyles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$background: teal;
$jumbotronBackground: darkseagreen;

.result-background {
background-color: $background;
}

:global(.jumbotron).result-background {
background-color: $jumbotronBackground;
display: block;
}
Loading

0 comments on commit 0f6dc57

Please sign in to comment.