Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

window undefined in preload #533

Closed
Vishwaas opened this issue Dec 12, 2018 · 10 comments
Closed

window undefined in preload #533

Vishwaas opened this issue Dec 12, 2018 · 10 comments

Comments

@Vishwaas
Copy link

Vishwaas commented Dec 12, 2018

Hi
When I try to access window object when running within preload of the index.html route(basically first route) I get window as undefined.

My webpack is as below:

client: {
		entry: config.client.entry(),
		output: Object.assign({ globalObject: 'this' }, config.client.output()),
		target: 'web',
		resolve: {
			extensions: ['.js', '.json', '.html'],
			mainFields: ['svelte', 'module', 'browser', 'main']
		},
		module: {
			rules: [
				{
					test: /\.scss$/,
					use: ['style-loader', 'css-loader', 'sass-loader']
				},
				{
					test: /\.css$/,
					use: ['style-loader', 'css-loader']
				},
				{
					test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
					use: [
						{
							loader: 'file-loader',
							options: {
								name: '[name].[ext]'
							}
						}
					]
				},
				{
					test: /\.html$/,
					use: {
						loader: 'svelte-loader',
						options: {
							dev,
							hydratable: true,
							hotReload: true,
							preprocess: {
								style: sassPreprocess
							}
						}
					}
				}
			]
		},
		mode,
		plugins: [
			dev && new webpack.HotModuleReplacementPlugin(),
			new webpack.DefinePlugin({
				'process.browser': true,
				'process.env.NODE_ENV': JSON.stringify(mode)
			})
		].filter(Boolean),
		devtool: dev && 'inline-source-map'
	},

	server: {
		entry: config.server.entry(),
		output: Object.assign({ globalObject: 'this' }, config.server.output()),
		target: 'node',
		resolve: {
			extensions: ['.js', '.json', '.html'],
			mainFields: ['svelte', 'module', 'browser', 'main']
		},
		externals: Object.keys(pkg.dependencies).concat('encoding'),
		module: {
			rules: [
				{
					test: /\.html$/,
					use: {
						loader: 'svelte-loader',
						options: {
							css: false,
							generate: 'ssr',
							preprocess: {
								style: sassPreprocess // enabled sass preprocessing for css within components. Requires style="text/scss" in tag
							},
							dev
						}
					}
				}
			]
		},
		mode: process.env.NODE_ENV,
		performance: {
			hints: false // it doesn't matter if server.js is large
		}
	},

	serviceworker: {
		entry: config.serviceworker.entry(),
		output: Object.assign(
			{ globalObject: 'this' },
			config.serviceworker.output()
		),
		mode: process.env.NODE_ENV
	}
@Conduitry
Copy link
Member

Code in preload is run on both the server and the client. When it is run on the server (when you first request a page), there's no window. If you want some code to run only on the client side for a component or page, you can put it in the oncreate lifecycle hook.

@Vishwaas
Copy link
Author

This is my logic:

  1. On preload I check the domain from which the call is made and based on that I chose a different URL
  2. Call the URL in preload since the data obtained from this call is required for that page

If I use on-create then the page does not wait for the call to be completed before loading the page?

Another point, this issue appears after I open the application on browser so I assumed it happens in browser But worst part is the error appears on node application and i cannot see the file in browser debugger.

When and What is the different activity happening in preload when run in server and client?

@Vishwaas
Copy link
Author

https://sapper.svelte.technology/guide#routing states that
When a user first visits the application, they will be served a server-rendered version of the route in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel.

So in-order to make sure window is available I created a dummy first route and inside the oncreate i re-routed to the main route, so shouldn't main route have window object now?

@johanalkstal
Copy link

johanalkstal commented Dec 13, 2018

@Vishwaas Since preload is called both on the server and on the client you can't just use window without checking if it exists first, since window is a browser feature and doesn't exist when the page is being server rendered.

This means that window will always become available after the page has been added to the DOM.

This gives you two choices,

  1. In preload you can check if window exists before using it
preload () {
    if (typeof window !== 'undefined') {
      // Do your window.location check here.
      this.redirect(307, '/somewhere')
    }
  },
  1. Use window in oncreate since this method is called once the component has been rendered to the DOM (but this.redirect does not exist here so you will have to use goto).

Both scenarios will display the page before a redirect happens though.

@Vishwaas
Copy link
Author

I am already doing this typeof window !== 'undefined'
Like I mentioned I just re-directed within oncreate so it worked fine for now, but as a framework I was just curious why this decision? It beats the point of preload hook if need to redirect it or use some sort of hack

@Conduitry
Copy link
Member

Conduitry commented Dec 13, 2018

The design decision was that preload would be for stuff that you would want to run for server-rendered pages and on client-side navigation. It sounds like what you really want is to be able to access the fully-qualified domain name used to access the page in preload. Is that correct? I don't think this is a particularly common use case. It definitely doesn't seem like something that would be impossible for Sapper to provide, but I'm going to defer to others on whether this is worth the complication.

I think something you could do now though is to create a piece of Express middleware that runs just before Sapper, which grabs req.headers.host and puts it on req.query. Then your preload can look at query.host (or whatever you decide to call it) - which will be there for all server-rendered requests - and to use window.location.host on the client.

@Conduitry
Copy link
Member

Closing, as I don't think this is something Sapper should itself provide.

@Conduitry
Copy link
Member

Change of heart on this one: We're probably going to go ahead with something like #735 which lets you access the page's host in a unified way across server and client in preloads and in the page store.s

@quantuminformation
Copy link

Is window supposed to be undef in _layout.svelte too?

@a-luna
Copy link

a-luna commented Jul 14, 2021

Xxx______..

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

No branches or pull requests

5 participants