Open Gennnji opened 4 years ago
Does the svelte-adapter work in Next.js? My next.js app can't recognize my svelte component. Cannot find module error.
I’m not 100% on SSR, svelte has separate SSR builds so that will need to be handled somewhere. I’ll take a closer look at this shortly.
Actually I realized adapter for Next.js for my work. If I'll have a time, I'll try to contribute.
@Gennnji I'd love to take a look at your approach if possible. There are a few ways around this, that I can think of, but I have some reservations about which way makes the most sense.
@pngwn Sorry for such late answer. Here is how I adapted your code for Next.js:
const React = require('react');
const createReactClass = require('create-react-class');
// useRef somehow errors with Next.js (maybe I couldn't handle it rightfully)
// So functional component became class component and also a CommonJS module
module.exports = function(Component, ComponentSsr, style = {}, tag = 'span') {
const ComponentAdapter = createReactClass({
getInitialState: function() {
this.container = React.createRef();
this.component = React.createRef();
const { head, html, css } = ComponentSsr && ComponentSsr.render
? ComponentSsr.render(this.props)
: { head: '', html: '', css: '' };
this.componentHtml = (css && css.code ? `<style>${css.code}</style>` : '') + html;
return {};
},
componentDidMount: function() {
if (!Component) {
return;
}
const eventRe = /on([A-Z]{1,}[a-zA-Z]*)/;
const watchRe = /watch([A-Z]{1,}[a-zA-Z]*)/;
this.component.current = new Component({
target: this.container.current,
hydrate: true,
props: this.props,
});
let watchers = [];
for (const key in this.props) {
const eventMatch = key.match(eventRe);
const watchMatch = key.match(watchRe);
if (eventMatch && typeof this.props[key] === 'function') {
this.component.current.$on(
`${eventMatch[1][0].toLowerCase()}${eventMatch[1].slice(1)}`,
this.props[key]
);
}
if (watchMatch && typeof this.props[key] === 'function') {
watchers.push([
// name of Svelte component prop being watched
`${watchMatch[1][0].toLowerCase()}${watchMatch[1].slice(1)}`,
// callback to run when Svelte component prop changes
this.props[key]
]);
}
}
if (watchers.length) {
const update = this.component.current.$$.update;
// Changed function to arrow function, so context wouldn't change
this.component.current.$$.update = () => {
watchers.forEach(([name, callback]) => {
// Starting from some version of Svelte names and values of props
// are in different places
const index = this.component.current.$$.props[name];
callback(this.component.current.$$.ctx[index]);
});
update.apply(null, arguments);
};
}
},
componentDidUpdate: function() {
if (this.component.current) {
this.component.current.$set(this.props);
}
},
componentWillUnmount: function() {
if (this.component.current) {
this.component.current.$destroy();
}
},
render: function() {
return React.createElement(tag, {
ref: this.container,
style,
dangerouslySetInnerHTML: {
__html: this.componentHtml,
},
});
}
});
return function(props) {
return React.createElement(ComponentAdapter, props);
}
}
For using in Next.js I generate two bundles for Svelte App: client-side and SSR. Also I use CommonJS module so Next.js could run SSR without errors (maybe I just haven't configure webpack rightfully). Oh, and I use UMD bundles for Svelte App, both for client-side and SSR, so Next.js could get identical html renders for both sides. One more, among other updates I made fix for searching watchers for last versions of Svelte. Here are lines of code:
// Starting from some version of Svelte names and values of props
// are in different places
const index = this.component.current.$$.props[name];
callback(this.component.current.$$.ctx[index]);
@pngwn Yeah, just found concrete version of Svelte where changes for $$.props and $$.ctx were made to use bitmask for change tracking - https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3160 - Svelte v3.16 Commit - https://github.com/sveltejs/svelte/pull/3945
It will be very useful to make Svelte-components for use in SSR Frameworks such as React-based Next.js and Vue-based Nuxt.js. Maybe, after implementation an adapter for Angular, there will be a usefulness in adapter for Angular Universal.