Skip to content
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

Webpack-dev-server support? #8

Closed
mnpenner opened this issue Feb 5, 2017 · 5 comments
Closed

Webpack-dev-server support? #8

mnpenner opened this issue Feb 5, 2017 · 5 comments
Assignees

Comments

@mnpenner
Copy link

mnpenner commented Feb 5, 2017

First of all, great plugin!

However, it doesn't seem to work with webpack-dev-server because that runs on a separate domain. Is there any chance you can add an option to inject the SVG into the page via AJAX so that we can work around this?

@bensampaio
Copy link
Owner

bensampaio commented Feb 6, 2017

@mnpenner I used webpack-dev-server for the React example and it works. Could you have a look at it and see if it applies to your use case? Otherwise can you be more specific? Thank you :)

@bensampaio bensampaio self-assigned this Feb 6, 2017
@mnpenner
Copy link
Author

mnpenner commented Feb 7, 2017

Just tested your React example. It does indeed work with webpack-dev-server like you said, but you're not running it on a separate port.

I believe I had to run mine on a separate port because my app is written in PHP and its behind nginx. So I have nginx running on port 8080 and webpack-dev-server serving my compiled assets from 8081.

Here's the relevant part of my config:

if(isWDS) {
    let wdsPort = 8081;

    module.exports = merge(commonConfig, {
        output: {
            publicPath: `http://localhost:${wdsPort}/assets/`,
            filename: '[name].js'
        },
        entry: {
            all: [
                `webpack-dev-server/client?http://0.0.0.0:${wdsPort}`,
                'webpack/hot/only-dev-server',
            ]
        },
        devServer: {
            hot: true,
            host: '0.0.0.0',
            port: wdsPort,
            stats: 'errors-only',
        },
        devtool: '#inline-source-map'
    });
}

So what ends up happening is that your SVG looks like this:

<svg viewBox="0 0 216 146">
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/img/sprite.svg#icon-example-867aa"></use>
</svg>

And mine looks like this:

<svg viewBox="0 0 100 100">
    <use xmlns:xlink="http://www.w3.org/1999/xlink"
         xlink:href="http://localhost:8081/assets/sprite-4faa5ef477.svg#icon-asterisk-50af6"></use>
</svg>

Which causes it to be blocked by the browser (with no useful information):

image

I'm still looking for workarounds, but right now it appears to only workaround is to AJAX-in the SVG.

This wouldn't just be a problem for people using webpack-dev-server like me, but anyone who wants to use a CDN.

@mnpenner
Copy link
Author

mnpenner commented Feb 7, 2017

I gave this some thought and worked out a hack I can use for development:

First, update the <Svg> component to rip off the file path, leaving only the #hash:

export default function Svg(props) {
    let attrs = _.omit(props, ['sprite','title','desc']);
    let symbol = props.sprite.symbol;
    if(__DEV__) {
        symbol = symbol.slice(symbol.indexOf('#'));
    }
    return (
        <svg viewBox={props.sprite.viewBox} {...attrs}>
            <use xlinkHref={symbol}>
                {props.title ? <title>{props.title}</title> : null}
                {props.desc ? <desc>{props.desc}</desc> : null}
            </use>
        </svg>
    );
}

Then, in one of your scripts that loads on every page, inject the sprite:

if(__DEV__) {
    let spritemap = require('../icons').asterisk.symbol;
    spritemap = spritemap.slice(0, spritemap.indexOf('#'));
    fetch(spritemap).then(res => res.text()).then(text => {
        let div = document.createElement('div');
        div.innerHTML = text;
        div.style.display = 'none';
        document.body.insertBefore(div, document.body.childNodes[0]);
    });
}

N.B. I've picked a random sprite here so that I could get the filename since it's not exported.

__DEV__ is a "constant" I'm injecting through webpack.config.js:

        plugins: [
            new webpack.DefinePlugin({
                __DEV__: JSON.stringify(true),
            }),
        ],

In theory, those chunks of code should be compiled out for production, but I haven't actually verified that yet :-)

This will work for me for now I think, but this would be much better as a loader option. Maybe something like inject=true would cause all the symbol and view URLs to contain only the hash, and then it could inject something like I've done into the bundle to fetch the sprite and inject it into the page. Maybe something a little more robust though.

My solution won't work for CSS.

@bensampaio
Copy link
Owner

@mnpenner, I understand the problem. I am not using webpack-dev-server yet so I never came across this problem. Can't webpack-dev-server be used as a proxy for your PHP app? In this way none of this would be necessary.

This loader has to work for CSS and JS. That's one of the reasons that made me write it, so I won't implement something that removes support to CSS (even if it's under a specific flag).

@mnpenner
Copy link
Author

@bensampaio I think had problems proxying the requests last time I tried. Don't remember what issues I faced exactly.

I understand your position though. Being able to use SVGs in CSS is definitely a perk. It's a shame cross-domain <uses> still don't work in 2017. Browsers need to get their act together 😝

svgxuse works for HTML/JS. I was afraid it wouldn't work well with React because none of the SVGs are in my initial HTML, but it looks like it watches for DOM changes. However, it lets all the broken cross-domain requests fail before patching them which is kind of annoying.

I'm not sure what the answer is right now. If we AJAX-in the SVG, it doesn't help with CSS, and we have a FOMI (flash of missing icons). If we inline the spritemap, we lose out on caching. And if we use an external spritemap, we can't use a CDN/separate asset server. There's no winning!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants