Open shshaw opened 6 years ago
These are the main areas where DOM manipulation happens that we'd need to figure out SSR methods for.
createElement
: https://github.com/shshaw/Splitting/blob/master/src/utils/dom.js#L24
splitText
: https://github.com/shshaw/Splitting/blob/master/src/utils/split-text.js#L13
Splitting.html
: https://github.com/shshaw/Splitting/blob/master/src/core/splitting.js#L48
Undom may be a good "recommend to the user" solution. https://github.com/developit/undom
Re: our recent conversation with @towc
Utilizing an internal createElement
function adhering to basic JSX principles may allow us to add a Splitting.jsx
for use with React & Vue's render
functions.
shshaw [9:23 AM] What’s the cross-framework alternative to the :warning:DANGEROUS:warning: way? :slightly_smiling_face:
notoriousb1t [9:24 AM] maybe there is a way to pass in the element factory? This would also work for vue jsx
towc [9:24 AM] @shshaw don't think there is one :stuck_out_tongue: (edited) you write "bindings", I guess so the core library just glues together different bindings that's kind of how mobx/redux work for hooking into react component lifecycle stuff (edited)
notoriousb1t [9:25 AM] so
Splitting.jsx({ root: <Something></Something>, factory: React.createElement, by: 'chars' })
or something like that
shshaw [9:26 AM] Hm, I could see that working.
notoriousb1t [9:26 AM] I'm just not sure if you can use setAttribute etc on jsx elements in render()?
shshaw [9:27 AM] True… Might have to have our own version of
createElement
that’s used internally? For the regular splits & element creationsnotoriousb1t [9:28 AM] if jsx elements have enough of the node interface, we can just make createElement passed in as a default option and provide an override I have just never tried to mutate a react or vue jsx element in the actual render method
towc [9:30 AM] they both try to keep the view away from the model. You're trying to directly access the view, which... well...
notoriousb1t [9:31 AM] I think the best way to think of it is a post-processor for the render() function, so a transform for the view (not a model strictly speaking)
towc [9:33 AM] maybe you can hook into the react-dom package
shshaw [9:33 AM] If we did a
Splitting.jsx
style approach, that might solve prerendering/SSR as well. With a little shifting of the internals, we could use our owncreateElement(tagName, attributes)
for most of it the directSplitting.jsx
method would just bypass where we add classes to the targetted element, and would instead create the element directly likeSplitting.html
notoriousb1t [9:49 AM] It just depends on what we have available in the render function. If we can't mutate the elements, it might make sense to do internal json and then have a rendering phase
but that might make reusing existing elements interesting
shshaw [9:50 AM] Hm. It may be about the same. We’re only injecting our create elements into existing elements, not modifying them directly (except a class addition) So at each “text node only” level, we utilize the JSX/JSON style creation.
notoriousb1t [9:58 AM] I don't know... maybe creating splitting-react component would be the simplest way to provide first level support it doesn't help in SSR, but it would not require any rework of the library
davidkpiano [1:24 PM] wish list btw:
Splitting.objects(someElement)
just give me an array of[{ word: 'foo', letters: ['f','o','o'] }, .. ]
whatever internal structure you have orSplitting.objects(someSentence)
even you want full framework/front-end/back-end support? that's how ya do itshshaw [2:01 PM] How would you utilize Splitting.objects in a React setup in a meaningful way?
davidkpiano [2:02 PM] well that could be an internally used API for something like...
<Split message={message.text} />
davidkpiano [2:03 PM] see above ^ that'd be a good API for React
davidkpiano [2:04 PM] you don't need innerHTML internally, it would be...
Since a lot of this is about React, here's a potential solution that could be offered as a separate include in the main Splitting repo:
https://codepen.io/shshaw/pen/b9ff364ed9c1ca5d6efffc68317b8de5/
class Split extends React.Component {
target = React.createRef();
split = () => {
if ( this.target.current ) {
Splitting({ target: this.target.current, ...this.props });
}
}
componentDidMount = this.split;
componentDidUpdate = this.split;
render(){
return (
<div ref={this.target} {...this.props}>
{this.props.children}
</div>
)
}
}
This may be a little "un-React-y", but here's a functional component way that could prevent needing to import React or anything within the Splitting Repo while offering a splitting.jsx.js
for use in React projects.
https://codepen.io/shshaw/pen/c2f69f5ac0f1e3e51ac4560669eba50b?editors=0010
function SplittingWrap({ splitting, ...props}) {
let target;
setTimeout(() => {
if ( window && document && target ) {
Splitting({ ...splitting, target: target, });
}
});
return (
<span ref={(el) => { target = el; }} {...props}>
{props.children}
</span>
)
}
@shshaw Any updates on this? I'm doing a project based on NextJS and can't easily use Splitting because it relies on document or window 😿
@shshaw Will the proposed solution work with server side rendering, right I am trying to develop my portfolio website using gatsby and for fancy stuff using splitting.js but I am not able to build since importing splitting module itself uses document
@shshaw Sadly can't get it to work even with you proposed "un-React-y" example! Any ETA on this? PS: Sorry to bother you with this during the holidays! Please enjoy the free time and don't feel pressured to help right away! :)
Same here, not working with next.js, I get ReferenceError: document is not defined
triggered by module.exports = require("splitting");
If you're running Vue 3, we've just created a lite adaptation of Splitting designed for Vue 3 which is fully SSR compatible (that's why we made it)
With
Splitting.html
, it would be fantastic to offer server side rendering support so pre-compiled pages could have elements pre-split so that Splitting wouldn't even need to be delivered to or run on the client.Currently with VuePress, I'm having to do something like this in the
mounted()
function to ensuredocument
is available:Is it possible to utilize JSDOM when Splitting is called server side without delivering JSDOM to the client in the case of Vue components that would utilize Splitting?
Some suggestions from @visiblecode, using a JSON based approach, but this would likely require major restructuring of the way we handle splits:
String approach: