Skip to content

Commit 0346549

Browse files
authored
feat: support CRA-style proxy config (#1674)
1 parent 8d3bd42 commit 0346549

File tree

7 files changed

+90
-2
lines changed

7 files changed

+90
-2
lines changed

.changeset/five-peas-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-cli': minor
3+
---
4+
5+
Supports consuming "proxy" from package.json to proxy API requests in watch mode

packages/cli/lib/lib/webpack/webpack-client-config.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,43 @@ function isProd(env) {
278278
return prodConfig;
279279
}
280280

281+
function setupProxy(target) {
282+
if (!target) {
283+
return;
284+
}
285+
286+
const errorTemplate = warn =>
287+
`Invalid proxy configuration in package.json. ${warn} Skipping and using default.`;
288+
289+
if (typeof target !== 'string') {
290+
warn(errorTemplate('If provided, "proxy" must be a string.'));
291+
return;
292+
} else if (!/https?:\/\//.test(target)) {
293+
warn(
294+
errorTemplate(
295+
'If provided, "proxy" must start with "http://" or "https://".'
296+
)
297+
);
298+
return;
299+
}
300+
301+
return {
302+
target,
303+
logLevel: 'warn',
304+
context: (pathname, req) => {
305+
return (
306+
req.method != 'GET' ||
307+
(!(/^\/?assets/.test(pathname) || pathname.startsWith('/ws')) &&
308+
req.headers.accept.indexOf('html') === -1)
309+
);
310+
},
311+
secure: false,
312+
changeOrigin: true,
313+
ws: true,
314+
xfwd: true,
315+
};
316+
}
317+
281318
/**
282319
* @returns {import('webpack').Configuration}
283320
*/
@@ -315,6 +352,7 @@ function isDev(env) {
315352
logging: 'none',
316353
overlay: false,
317354
},
355+
proxy: setupProxy(env.pkg.proxy),
318356
},
319357
};
320358
}

packages/cli/tests/build.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ describe('preact build', () => {
7373
// The tsconfig.json in the template covers the test directory,
7474
// so TS will error out if it can't find even test-only module definitions
7575
shell.cd(dir);
76-
shell.exec('npm i @types/enzyme enzyme-adapter-preact-pure');
76+
//shell.exec('npm i @types/[email protected] enzyme-adapter-preact-pure');
77+
// Remove when https://github.com/preactjs/enzyme-adapter-preact-pure/issues/161 is resolved
78+
shell.exec('rm tsconfig.json');
7779

7880
expect(() => build(dir)).not.toThrow();
7981
});

packages/cli/tests/server.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,10 @@ exports.getServer = (dir, port = 3000) => {
66
maxAge: 0,
77
single: true,
88
};
9-
return polka().use(sirv(dir, opts)).listen(port);
9+
return polka()
10+
.use(sirv(dir, opts))
11+
.get('/proxied/request', (_req, res) => {
12+
res.end('Hello World!');
13+
})
14+
.listen(port);
1015
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { h } from 'preact';
2+
import { useEffect, useState } from 'preact/hooks';
3+
4+
export default () => {
5+
const [val, setVal] = useState('');
6+
7+
useEffect(() => {
8+
fetch('/proxied/request')
9+
.then(res => res.text())
10+
.then(data => setVal(data));
11+
}, []);
12+
13+
return <h1>Data retrieved from proxied server: {val}</h1>;
14+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"private": true,
3+
"name": "preact-proxy",
4+
"proxy": "http://localhost:8086"
5+
}

packages/cli/tests/watch.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ const { resolve } = require('path');
33
const startChrome = require('./lib/chrome');
44
const { create, watch } = require('./lib/cli');
55
const { determinePort } = require('../lib/commands/watch');
6+
const { subject } = require('./lib/output');
7+
const { getServer } = require('./server');
68

79
const { loadPage, waitUntilExpression } = startChrome;
810
let chrome, server;
@@ -62,6 +64,23 @@ describe('preact', () => {
6264

6365
server.close();
6466
});
67+
68+
it('should proxy requests when "proxy" exists in package.json', async () => {
69+
const api = getServer('', 8086);
70+
let app = await subject('proxy');
71+
72+
server = await watch(app, 8087);
73+
74+
let page = await loadPage(chrome, 'http://127.0.0.1:8087/');
75+
76+
await waitUntilExpression(
77+
page,
78+
`document.querySelector('h1').innerText === 'Data retrieved from proxied server: Hello World!'`
79+
);
80+
81+
server.close();
82+
api.server.close();
83+
});
6584
});
6685

6786
describe('should determine the correct port', () => {

0 commit comments

Comments
 (0)