I'm using SSR to render a react component which should import an image. I've added:
declare module '*.ico' {
const value: any
export default value
}
Which works. Then when I try to do:
import Favicon from '/path/to/favicon.ico'
I get an error "SyntaxError: Invalid or unexpected token". I get this error even if I don't even attempt to use it, it breaks on the import itself:
SyntaxError: Invalid or unexpected token
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
I'd ask how I can then use it but I'm first stuck on just even importing it before I'll attempt to use it.
Note, I don't want to rerun webpack or anything like that when rendering a single component server side, so how can I use an image with an import without using webpack.
I'm starting to think that only way to achieve this is to manually use fs.writeFile and to assign the static URL manually to the image source, but I was hoping there's an easier solution than that, I assume webpack is doing all that under the hood.
EDIT: I thought I'd found a solution to this but still no luck.
You can have something like this, which can render a page:
export const component = async (
request: Request,
response: Response,
): Promise<void> => {
console.log(request.url)
const stream = renderToNodeStream(<Component />)
stream.pipe(response)
stream.on('end', () => {
response.end()
})
}
Just about every blog post and example on the internet stops there and says "ay okay, job done", but it's not, that's not even nearly half the story.
When you use the above along with:
import Favicon from '/path/to/favicon.ico'
Inside that component, then it will break because typescript can't parse any images, it makes sense. It will also break on any CSS or anything else that isn't react. What that means is that you can't reuse any client side components and rerender them on the server, not if they include any images or any CSS or anything that isn't pure typescript/react.
You can use:
import webpack from 'webpack'
import config.js from './config'
...
const compiler = webpack(config('production'))
compiler.run((error, stats) => {
compiler.close()
})
And using that you can compile and bundle specific files with webpack and invoke it programmatically, but that doesn't really solve the problem. I don't get why every example out there just shows renderToStaticMarkup or renderToString when not a single one of them tells you "oh by the way using that on anything you have will break." It's not possible to run or use or utilize react-dom/server in any useful way if you don't precompile it with webpack and run a webpack compiler on every prerendered HTML before fs.readFile'ing that *.html and feeding it to react's render.
You also can't just manually use <img src='/path/to/image'/> because then your server and client code will not be the same so hydrate will complain, since webpack is rendering the images in a different way than you're manually doing, not to mention that you can't reuse the same components with something like import Component from './component', you'll have to duplicate your entire code base, once for webpack client and once for manually writing image paths.
So how can you simply render an image using renderToString, I don't get how nobody out there and no blog post and no discussion forum or no nothing has any information on this?! More than that why does everyone simply say "oh just use renderToString and voila", when it clearly doesn't work for images/css or anything else.
What's the puzzle piece I'm missing, am I missing something really stupid or obvious?