-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: custom proxy settings #208
Comments
Published import storybook from '@kadira/storybook/dist/server/middleware';
// ...
app.use(storybook(configDirectory));
// ... Check this line |
Wow, this is awesome. I will definitely try it out. Feel free to close this issue. Update: it worked perfectly. This really adds much flexibility to how you can setup your storybook. Nice! |
@yianL do you mind sharing the config sample you are using that works with storybook? |
@maxww What kind of example are you looking for? |
We should document this ability better I think. |
@ndelangen I don't have server side and one of the components is using xhr to make ajax call get fetch more data. I want to write the webpack.config to be able to do like
I've tried it to be inside and outside the devSever object, no luck. |
@maxww Here's a sample of my setup: var Express = require('express')
var proxy = require('http-proxy-middleware')
var storybook = require('@kadira/storybook/dist/server/middleware').default
var app = new Express()
var port = 4001
var storybookConfig = './.storybook'
app.use(storybook(storybookConfig))
app.use('/api', proxy({
target: 'https://api-endpoint', // target host
changeOrigin: true,
}))
app.listen(port, function (error) {
if (error) {
console.error(error)
} else {
console.info('==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port)
}
}) Let me know if you have any questions. Oh btw, this worked for me in storybook |
I have to say that's some creative usage, but I cannot recommend anyone to use files deep into an package. We cannot and will not guarantee those files will stay in those location or contain the same exports. It's not our API. Including storybook inside an express app is a use case ew haven't seen much so far; though I'm interested in supporting it officially at some point. @maxww storybook HAS a 'backend' and it's express. By adding a I guess you can try and do the same inside a webpack config, I don't know I've never tried that. |
I don't understand how you say you don't have a backend, but you component is fetching data somewhere? Do you mean you're building storybook to a static site? |
UPDATE: I see now in #445 that proxy configuration with Webpack was requested at some point and not recommended. I also see that there was once a local database add-on, but it appears to be discontinued (although it does look as though parts of it may be integrated into this repository). I'm still a bit confused as to what is working and what is not, what is recommended, what is supported, etc. when it comes to proxying. It seems there is sparse documentation for using the middleware as well. I'd love to help develop and document this as soon as I have a better understanding of what currently exists and in what direction the team plans to move this feature with Storybook v3. I'm not sure if this is what @maxww was getting at, but I'm wondering about a similar situation in which I "don't have a backend", meaning that I am calling an external API for my data. TL;DRIs there a way for me to initialize Storybook with an API proxy without having a local Express server or Initializing Storybook with an API ProxyI am using Create React App for my React project now, and would love to find a way in which I can still call the API endpoints when using Storybook. CRA makes use of a ( "proxy": "https://api-endpoint.com"
Ideally, I would love to keep this working with isolated components in Storybook, so that things like an autocomplete search form can be properly used, styled, and tested. I currently have this working by using Storybook environment variables. (As an aside, I don't know if the documentation for environment variables is still actively being kept up-to-date, as I only found it via a Google search, and it does not appear anywhere as a clickable link within the Storybook column nav panel in the official documentation.) const apiUrl = process.env.REACT_APP_API_URL || process.env.STORYBOOK_API_URL
export const searchSuggestions = fragment =>
fetch(`${apiUrl}/autocomplete/v1/suggestions/${fragment}`) I then start Storybook like STORYBOOK_API_URL="https://api-endpoint.com" yarn storybook And now I can make calls the the API endpoints using the same proxy method that Create React App allows me to use. However, this feels a bit hacky, and goes against what the Storybook environment variables docs recommend
Is it possible to initialize Storybook with an API proxy without having to run my own Express server or editing the webpack config directly? Perhaps some form of middleware in the Storybook setup? If this is not possible, then are there any foreseeable repercussions with the current method I have set up that uses a Storybook environment variable? |
@indiesquidge wanna do a 1 on 1 talk about thi topic in a sky call or something? talk to me on slack 👍 |
@ndelangen, just when I saw your message I was able to find a solution to my problem using the awesome middleware customization roughly outlined in #435. It is a very similar solution to @yianL's solution above, only I am not creating my own Express server and instead leveraging Storybook's router handler in the middleware. I have the following in const proxy = require('http-proxy-middleware')
module.exports = function expressMiddleware (router) {
router.use('/api', proxy({
target: 'https://api-endpoint.com',
changeOrigin: true
}))
} This has a dependency on the It uses a proxy function to map a context ("/api") to a target ("api-endpoint.com"). One thing to note is that the Thank y'all so much for exposing the middleware custom config in Storybook, that is a very helpful feature indeed 💛 |
@indiesquidge can you explain your workflow a bit more? so you have stories for container-style components that are end-to-end connected to your live API? Or do your stories grab the data from the server and then use it populate your components? Do you have any public examples of stories like this I can look at, either in a repo or just comment here or create a gist? Super curious. |
Yeah, this is more inline with what I am working with. Unfortunately I don't have a public example to show, but the main component that was causing me grief was an Something like this export default class AutocompleteForm extends Component {
state = {
fragment: '',
suggestions: []
}
handleSearch = fragment => {
return api
.searchSuggestions(fragment)
.then(api.validateResponse)
.then(api.toJSON)
.then(json => json.suggestions.map(s => s.term))
.then(suggestions => this.setState(() => ({ suggestions })))
.catch(() => this.setState(() => ({ suggestions: [] })))
}
onChange = e => {
const fragment = e.target.value
this.handleSearch(fragment)
this.setState(() => ({ fragment }))
}
render () {
const { fragment, suggestions } = this.state
return (
<form>
<label htmlFor='product-search'>Search</label>
<input id='product-search' value={fragment} onChange={this.onChange} />
</form>
<ul>
{suggestions && suggestions.map((suggestion, i) => <li key={i}>{suggestion}</li>}
</ul>
)
}
} The real component is a bit more complex, but this is the gist of it. I'd like to be able to show the suggestions list of
const apiUrl = process.env.REACT_APP_API_URL || ''
export const searchSuggestions = fragment =>
fetch(`${apiUrl}/api/autocomplete/v1/suggestions/${fragment}`) |
@indiesquidge Thanks for sharing! I think this would make an awesome blog post once you're happy with a solution. Would be thrilled to publish it on Storybook's Medium publication if that's at all interesting: https://medium.com/storybookjs |
@shilman, that sounds great! I'll work on something this week and get back to you soon :) |
It's really a useful feature, since the I am willing to create a PR for this part of doc. |
A PR on our docs to improve the information regarding |
I will work on it. 😋 |
Any news? I want to connect Apollo Graphql and i need this option (Like proxy config in create-react-app). Thank you :) |
@hmontes This is how I did: // .storybook/middleware.js
const proxy = require('http-proxy-middleware')
const packageJson = require('../package.json')
module.exports = function expressMiddleware(router) {
const proxyConfig = packageJson.proxy || {}
for (let domain in proxyConfig) {
if (typeof proxyConfig[domain] === 'string') {
console.log(domain)
router.use(domain, proxy({
target: proxyConfig[domain]
}))
} else {
router.use(domain, proxy(proxyConfig[domain]))
}
}
} // package.json
{
"proxy": {
"/api": "http://localhost:5000/api"
}
} |
anyone would add the doc for allowing webpack dev server proxy into the storybook? |
this should add into the doc...
|
To make it API-compatible with CRA, the following works: const proxy = require('http-proxy-middleware');
const { proxy: proxyConfigs } = require('../package.json');
module.exports = router =>
Object.keys(proxyConfigs).forEach(key =>
router.use(key, proxy(proxyConfigs[key]))
); IMO this should be added as a default to storybook, since it does say that it bases the default setup on CRA. |
@chrbala what is CRA? |
Who's using Angular, can use what @djyde did but simply use the const proxy = require('http-proxy-middleware')
const proxyConfig = require('../proxy.conf.json')
module.exports = function expressMiddleware(router) {
Object.keys(proxyConfig).forEach(domain => {
const target = proxyConfig[domain];
if (typeof target === 'string') {
console.log(domain)
router.use(domain, proxy({ target }))
} else {
router.use(domain, proxy(proxyConfig[domain]))
}
});
} |
I am using Angular. Is there a way to do proxy per story instead of per the whole storybook? |
@dereklin you can add some prefix for earch story on the API request and re-write it on the proxy it-self :) |
Hi @picheli20 Thanks for the snippet. I have copied it to Any ideas? |
@dtslvr and the same request to the backend works? Looks like that the request is going wrong, not the proxy |
Wow, you're right 😀 The request is unauthorized because of a missing token. I was confused of the request to |
Please use createProxyMiddleware, function is updated const { createProxyMiddleware } = require('http-proxy-middleware'); |
FYI all of these APIs are experimental/undocumented, and we reserve the right to change/remove them outside of the normal rules of semver. |
This worked for me in an Angular project |
This did the trick for me, but it doesn't work if it's a TypeScript file. I had to rename it from Note: I'm using Storybook 7.0.0-rc.5 with vite |
Works for me, "http-proxy-middleware": "^2.0.6",
|
Not a bug, it should be Long term we'd like to come up with a way to add serverside routes support to storybook that will be statically build. |
working for me:
|
First of all, great work with react-story book! I love how I can now jump between different states of my components quickly, and work on the visual changes.
So I have a component that fetches data from an api, and plots it onto a chart. Although I can write a story and feed mocked data into the component, sometimes it's helpful to render the "smart" version of the component and see it in real action. Problem is, I used to setup my own express server with webpackDevMiddleware, and then configure proxies so I can redirect api calls to another port. I couldn't find a way to setup similar configuration when using react-storybook. I ended up with a hack by going into
node_modules/.bin/start-storybook
and put my proxy settings there.I'm not sure if this is a use case the authors intended to support, but I think it'll be really nice if I can use react-storybook as a playground for all sorts of components, whether they're dumb or smart. To achieve that, we would need a way to support custom proxy settings.
The text was updated successfully, but these errors were encountered: