SyntaxError Invalid or unexpected token - How to SSR images css with react

0 votes

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 use it after that, but I'm stuck on how to even import it before I can try to utilise it.

Note that when rendering a single component server side, I don't want to rerun webpack or anything like that, thus how can I utilise an image with an import without using webpack?

I'm starting to believe the only way to accomplish this is to use fs.writeFile and manually set the static URL to the image source, but I was hoping there was a better approach; I suppose webpack handles everything behind the scenes.

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'

It will break inside that component since typescript can't read any pictures, which makes reasonable. It will also break on any CSS or other non-reacting elements. That implies you can't reuse any client-side components and re-render them on the server if they contain any pictures, CSS, or other non-typescript/react elements.

You can use:

import webpack from 'webpack'

import config.js from './config'

...

const compiler = webpack(config('production'))

compiler.run((error, stats) => {
  compiler.close()
})

It will break inside that component since typescript can't read any pictures, which makes reasonable. It will also break on any CSS or other non-reacting elements. That implies you can't reuse any client-side components and re-render them on the server if they contain any pictures, CSS, or other non-typescript/react elements.

You can't just use manually because your server and client code will be different, causing hydrate to complain, because webpack renders the images differently than you are manually doing. You also won't be able to reuse the same components with something like import Component from './component' because 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'm not sure how nobody has any information on this, no blog post, no discussion thread, no nothing?! Furthermore, why does everyone simply say, "Oh, just use renderToString and voila," when renderToString obviously does not work for images, CSS, or anything else?

Is there a puzzle piece I'm missing, or am I overlooking something obvious?

Jun 1 in CSS by Edureka
• 9,760 points
445 views

1 answer to this question.

0 votes

The first thing to highlight is that using any react server methods without some sort of bundler like webpack isn't possible, or it is possible but makes no sense because you'll have images, CSS, and other stuff that typescript can't comprehend.

The first thing you'll need is the normal webpack config that you're used to:

const config = {
  output: {
    path: path.join(__dirname, 'public'),
    filename: '[contenthash].js',
    assetModuleFilename: '[contenthash].[ext]',
    publicPath: '/',
    libraryTarget: 'umd',
    clean: false,
  },
  target: 'web',
  resolve: {
    extensions: ['.js', '.ts', '.jsx', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: [/node_modules/],
      },
      {
        test: /\.(jpg|png|ico)$/,
        type: 'asset/resource',
        generator: {
          filename: '[contenthash].[ext]',
        },
      },
    ],
  },
  ...

It's not the complete config but it will give a general idea. There you can use all the normal plugins and stuff you're used to, i.e. file-loader or style-loader or whatever.

After that assume that you have a directory structure like this:

- webpack.config.js
- ui/route // we want all files here to be SSR and client side rendered

Then you can bundle all of that like you normally do and serve it client side using your normal webpack setup. However in addition to that you'll need some kind of a compiler to write your .js files in order to be consumed by react server functions. This is the key part.

import fs from 'fs'
import path from 'path'
import webpack from 'webpack'

import config from '../webpack.config.js'

const configuration = config({production: true})

const files = fs.readdirSync(path.join(__dirname, 'ui/route'))

for (const file of files) {
  if (file.indexOf('.map') === -1) {
    configuration.target = 'node'
    configuration.entry = path.join(__dirname, 'ui/route', file)
    configuration.output.path = path.join(__dirname, '../public')
    configuration.output.filename = file // [contenthash].js

    const compiler = webpack(configuration)
    compiler.run((error) => {
      console.log(error)

      compiler.close((error) => {
        console.log(error)
      })
    })
  }
}

That code is fairly raw and can still be optimised in a variety of ways, but it demonstrates what you can achieve. You can either do each file individually, or you can use a glob to read everything from a specific directory (or search it recursively), then programmatically invoke the webpack compiler and output each file (page (route)) separately to their directories as.js files, each with their own CSS/Images/whatever already compiled with webpack. Something to keep in mind here is that you don't need to build separate webpack configurations for no reason; all you need to change is the target to node, the entry, and the output, and you can do it with the original webpack configuration.

Then you can include this compiler in your build phase so that you can start the server with something like tsc && node lib/compiler.js && lib/server.js every time. This will create everything, then call webpack on everything and output the files, after which you may start the server. You can also do it dynamically if you choose. What's crucial here is that typescript should only compile your server-side scripts, whilst webpack (using ts-loader to invoke typescript) should compile your UI files.

answered Jun 1 by Edureka
• 9,540 points

Related Questions In CSS

0 votes
1 answer

Rails - how to integrate a form with bootstraps css?

Here is how I did it  in my ...READ MORE

answered Jun 28 in CSS by Edureka
• 9,540 points
14 views
0 votes
1 answer

How can I use CSS to style multiple images differently?

You can do that in HTML (delete ...READ MORE

answered Jun 21 in CSS by Edureka
• 9,540 points
25 views
0 votes
1 answer

How to overlay image with color in CSS?

Use the rgba() Function to Overlay Background ...READ MORE

answered Jun 28 in CSS by Edureka
• 9,540 points
17 views
0 votes
0 answers

How to position text over an image with CSS

How can I use CSS to center ...READ MORE

Jul 11 in CSS by Edureka
• 9,760 points
9 views
0 votes
1 answer

How to set meta tags using Angular universal SSR and ngx-seo plug-in?

first Install the plug-in with npm i ngx-seo ...READ MORE

answered Feb 11 in Others by narikkadan
• 11,280 points
688 views
0 votes
1 answer

How to use next-seo for setting nextjs meta tag with multiple OGP images?

https://github.com/garmeeh/next-seo use this git repo that contains ...READ MORE

answered Feb 24 in Others by narikkadan
• 11,280 points
415 views
0 votes
1 answer

Facebook debugger does not pick up Next.js next-seo meta tags

It's a common pattern to have a ...READ MORE

answered Feb 26 in Others by narikkadan
• 11,280 points
1,613 views
0 votes
1 answer

How to set Bullet colors in UL/LI html lists via CSS without using any images or span tags

I use jQuery for this: jQuery('li').wrapInner('<span class="li_content" />'); & ...READ MORE

answered May 27 in CSS by Edureka
• 9,540 points
41 views
0 votes
1 answer

How to build a special polygon (a kite shape) with HTML & CSS only?

I made two divs, one for Arc ...READ MORE

answered May 28 in CSS by Edureka
• 9,540 points
65 views
webinar REGISTER FOR FREE WEBINAR X
Send OTP
REGISTER NOW
webinar_success Thank you for registering Join Edureka Meetup community for 100+ Free Webinars each month JOIN MEETUP GROUP