Giter Site home page Giter Site logo

preactjs / preact-render-to-string Goto Github PK

View Code? Open in Web Editor NEW
623.0 623.0 89.0 1.57 MB

:page_facing_up: Universal rendering for Preact: render JSX and Preact components to HTML.

Home Page: http://npm.im/preact-render-to-string

License: MIT License

JavaScript 99.90% TypeScript 0.10%
html preact preact-components universal

preact-render-to-string's People

Contributors

38elements avatar 9renpoto avatar aminnairi avatar andrewiggins avatar dbushong avatar developit avatar ftes avatar geo25rey avatar github-actions[bot] avatar glenchao avatar gpoitch avatar i-like-robots avatar johnhaitas avatar jovidecroock avatar jviide avatar loklaan avatar marvinhagemeister avatar mbrukman avatar mikestead avatar mtribes-sdk-bot avatar niedzielski avatar rschristian avatar shinyama-k avatar squidfunk avatar sventschui avatar toraora avatar utkarshkukreti avatar w4zzz4p avatar whilelucky avatar wildlyinaccurate avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

preact-render-to-string's Issues

Appears to be calling componentDidMount() during render

As far as I know, React.renderToString() never calls the componentDidMount() lifecycle hook, as the code in that hook (I would think almost always) only needs to run on the client for inserting various functionality into the view.

I had some calls to window within some of my components' compontentDidMount() hook to add an event here and there, and when crossing over and using preact-compat and I've been getting errors because Node obviously doesn't have access to the browser's window global variable.

Add option to render empty attributes

I use glamor for styling which renders data attributes for its css selectors. It looks like there was a change in v2.20.x that removed the values of the data attributes. It now produces html as the following:

<div data-css-19swgx6 />

The server rendering tests in glamor pass, so I assume that renderToStaticMarkup from react-server/dom renders the empty attributes, so it would be nice to have this as a little compatibility layer as well. Tracking this down, I was able to modify their tests to use render using this library and verified that the empty attributes weren't rendered, causing their tests to fail.

I've tracked it down to src/index.js#L137 which omits falsey values.

I am curious if this is an option you would consider adding? If so, I would be happy to submit a PR to add this as an opt-in feature.

Improve async handling

Hi
It would be good to have an interface like this:

render(
  <Provider store={store}>
    <Root/>
  </Provider>
).then(({html, context, state}) => { /* all done, serve to client now */ }

So the render promise will only resolve once everything has been rendered and all async actions have been finished. This would make it easier to get the redux state too and you wouldn't have to get the redux state artificially before calling render (plus artificially figuring out the route n stuff - all the things that make the server side different from the client side).
Basically run the complete application server side until its stabilized and ready to render.

doesn't work with react-ab-test

All components currently being ab-tested just end up rendering [object Object]. This only happens on the server side, so it's not a problem with preact

Is this known already? (and is there a workaround?) It appears to be the only thing blocking me from using preact

Don't return in getComponentName(), if `component.name === 'cl'`

In the same setup as #43

I noticed that when getComponentName() is called on inner === true VNodes, the resolution for the name of the component is often cl, even though proto.displayName or proto.name contains the name of the actual component.

The string cl is coming from this line: https://github.com/developit/preact-compat/blob/e25d0607d8a00a3e2f9229f33de4dc0f63c8e931/src/index.js#L405

I could fix this in the code with a simple if inside getComponentName:

if (component.name === 'cl') {
	delete component.name;
}

Again, I'm not sure if this is happening due to my setup with preact-compat or maybe it's related to the preact-compat-enzyme but it would be nice to know if this is intended operation of if I'm actually doing something wrong.

Can you help to figure this issue out as well?

defaultProps treated differently than in preact

This library behaves differently than preact when dealing with undefined prop values.

Expected behaviour:
preact-render-to-string should behave like preact:

  1. A default value is set for a prop (MyComponent.defaultProps.someProp = 'X')
  2. undefined is passed as prop value (<MyComponent someProp={undefined}/>)
  3. I expect to get the default value within the instantiated component (console.log(this.props.someProp) >> 'X')

Actual behaviour:
If undefined is passed as prop value, then this.props.someProp resolves to undefined.

Here you can see how the implementation in preact and preact-render-to-string differ:

for (let i in defaultProps) {
  if (props[i]===undefined) {
    props[i] = defaultProps[i];
  }
}
let defaultProps = vnode.nodeName.defaultProps,
  props = assign({}, defaultProps || vnode.attributes);
if (defaultProps) assign(props, vnode.attributes);

how to configure with preact-compat ?

I configured project as described in preact-compat

import React from 'react';
import render from 'preact-render-to-string';
import App from '../common/components/App.jsx';
import Container from '../common/components/Container.jsx';

export default function serverEntry() {
    return render(
        <Container>
            <App />
        </Container>
    );
};

when run - error throws: ReferenceError: h is not defined

using 'import { h } from 'preact'' instead of 'import React from 'react'' - doesn't help

createContext Consumer does not receive context

Rendering components using createContext fails.
Consumer components does not receive the context set in the Provider component.

renderToString should check if there's a contextType and a corresponding context.

SVG attributes format

Not sure if this an issue or a clarification.
If I have some SVG, such as
<path d="M 2 50 A 48 48 0 0 1 50 2" stroke="#gradLeft-1" strokeWidth="4" fill="none" />
It doesn't work correctly.
If I change 'strokeWidth' to 'stroke-width' (changed to lower case with a dash) then it does work ok.
This is different to react.
Is this behaviour correct? or have I done something wrong?

Getting a TypeError: preact_render_to_string_1.default is not a function when using with ts

I do not know if that is a transpilation problem, but it looks like that when you try to do the following with typescript:

import xyz from "module-with-default-export"

it assumes that a exports.default exists within module-with-default-export, which I think is right but it has been a while since I last checked the modules spec. It looks like preact-render-to-string directly exports a function.

Workaround is to do an:

import * as render from "preact-render-to-string"

But this is schematically wrong if I'm not mistaken.

Events not working

It seems DOM events are not working when using preact-render-to-string.

import { render } from 'preact-render-to-string';
import {h, Component} from 'preact';

class Page extends Component {
  click(event) {
    console.log(event);
  }

  render(){
    return <button onClick={this.click}>Click me!</button>
  }
}

const html = render(<Page />);

console.log(html);
// <button>Click me!</button>

Preact Version: 8.4.2
PreactRenderToString Version: 4.1.0

Skip `__source` and `__self` from `renderToJsxString`

I'm integrating preact-compat into create-react-app without ejecting and had quite a lot of success doing it so far.

My setup

For the Jest tests, I managed to use moduleNameMapper to use the preact-* testing utilities instead of anything from React, something similar to this:

{
	'^react-dom/server$': '<rootDir>/node_modules/preact-render-to-string/dist/index.js',
	'^react-dom/test-utils$': '<rootDir>/node_modules/preact-test-utils/lib/index.js',
	'^react-dom$': '<rootDir>/node_modules/preact-compat-enzyme/lib/index.js',
	'^react-test-renderer/shallow$': '<rootDir>/node_modules/preact-test-utils/lib/index.js',
	'^react-test-renderer$': '<rootDir>/node_modules/preact-test-utils/lib/index.js',
	'^react-addons-test-utils$': '<rootDir>/node_modules/preact-test-utils/lib/index.js',
	'^react-addons-transition-group$': '<rootDir>/node_modules/preact-transition-group/dist/preact-transition-group.js',
	'^react$': '<rootDir>/node_modules/preact-compat-enzyme/lib/index.js'
}

The issue

While running the Jest tests, I've run into an issue when using renderToJsxString directly to expect(renderToJsxString(<SomeComponent></SomeComponent>)).toMatchSnapshot(); there are __source and __self attributes on every component in the output.

The output looks similar to this:

<div
  __source={
    Object {
      "fileName": "<some-path-here>/src/components/mainframe/MainFrame.js",
      "lineNumber": 9
    }
  }
>
  <cl
    src=""
    id="main-app-iframe"
    __source={
      Object {
        "fileName": "<some-path-here>/src/components/mainframe/MainFrame.js",
        "lineNumber": 10
      }
    }
    class="tst-app-frame"
  >
  </cl>
</div>

I managed to fix this by supplying my own attributeHook, but it means that I needed to recreate all of the functionality from within which is not the best for keeping in sync with updates.

This is all I wanted to add inside attributeHook

if (name === '__source' || name === '__self') {
	return '';
}

The opts I'm passing to renderToJsxString are:

{
	jsx: true,
	xml: false,
	functions: true,
	functionNames: true,
	skipFalseAttributes: false,
	pretty: '  ',
	shallow: true,
	min: true,
	attributeHook // the one mentioned above
}

I'm not sure if this is by design, or something that only happens with preact-compat or if it's related to me using the moduleNameMapper setup written above.

The solution could be to have a switch to filter for these fields, it could be to have a blacklist of attributes or it could be that there's an error on my part.

Can you help to figure it out?

[SyntaxError] "Unexpected token <" [render(<App/>)]

I've got this error when I launch my node server :

    content: render(<App/>)
                    ^
SyntaxError: Unexpected token <
    at createScript (vm.js:53:10)
    at Object.runInThisContext (vm.js:95:10)
    at Module._compile (module.js:543:28)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:425:7)
    at startup (bootstrap_node.js:146:9)

Here's a sample of my server.js file (didn't show all the requires for instance).
I don't know what's wrong.
You can see I use preact-render-to-string and pass this rendering to my handlebar template.

The same technique is used there : https://github.com/jakearchibald/big-web-quiz/blob/master/server/views.js

const handlebars = require('handlebars');
const render = require('preact-render-to-string');
const index = require('../front/index');
/** @jsx h */

app.get('/', (req, res) => {
  res.send(index({
    css: ['/static/style.css'],
    lazyCss: ['/static/style.css'],
    scripts: ['/static/build.js'],
    content: render(<App/>)
  }));
});

renderToString( h( undefined ) ) returns [object Object]

Not sure if this is a preact issue or a preact-render-to-string issue, but Iโ€™ll put it here for now.

A component I wrote wasnโ€™t being exported properly (long story) and the result was undefined instead of a valid component. I thought it was a React alias issue like I saw in a few other issues, but after digging through my bundle I determined that that was not the case.

Seems to me that either h(undefined) or renderToString( h(undefined) ) should throw an error.

Issue: Multiple Renders - Different Data

Hello,

There seems to be an issue with calling the render function multiple times in the same file.

Example: I call the render function on the server twice with the same app but different data:

-server.js-

render(<App data={1}>) 
render(<App data={2}>)

but the render function seem to always pass the data from the first render.

-app.js-

console.log(props.data)
// 1
// 1

I have tried many scenarios but still same results.

Thank You!

Void elements render without a closing /

Currently the behaviour for void elements (img, br, etc) is that they render without a closing / โ€“ for example, <br> instead of <br/>.

Unfortunately this closing / is required for XHTML, meaning a Preact render won't validate against that content type. It's also a possible compatibility issue when using preact-compat, since React's own renderToString method adds the /.

The / is optional in HTML5, so I think rendering it out should resolve the above issues without breaking anything.

If this looks like a good idea, I'd be happy to submit a PR.

Thanks!

JSX renderer renders self closing tags wrong

Just noticed, that the jsx renderer double closes self closing tags like meta or base.

Test case:

const render = require("preact-render-to-string/jsx");

const html = <html><head><base href="foo/" /></head></html>;
console.log(render(html));
// Logs:
// <html>
//   <head>
//     <base href="foo/" /></base>
//   </head>
// </html>

Select value not rendered correctly

Credit goes to @kristoferbaxter for finding this:

<select value={2}>...</select> will output an attribute on the select, not on the correct option. The spec has this to say about values on a <select>-element:

The value IDL attribute, on getting, must return the value of the first option element in the list of options in tree order that has its selectedness set to true, if any. If there isn't one, then it must return the empty string.

On setting, the value attribute must set the selectedness of all the option elements in the list of options to false, and then the first option element in the list of options, in tree order, whose value is equal to the given new value, if any, must have its selectedness set to true and its dirtiness set to true.

So we need to set the selected property on the correct <option> child.

Allow override of `VOID_ELEMENTS`

In some instances, it's not desirable for certain tags to be treated exclusively as self-closing elements, such as with the <link> tag in RSS feeds. It might be useful to allow an additional option in the renderToString method to allow users to supply an array of elements they want (or as in this case, don't want) to be treated as self-closing. This may not really be used very much, but in cases where XML is generated, it could be a nice little feature to add.

If you're down, I'm happy to add it. I also see that this has been referenced in a somewhat different way in #52.

Couldn't find preset "es2015" relative to directory

I have my own .babelrc config (which doesn't include babel-preset-es2015)... why is preact requiring me to install and use the es2015 preset specifically?

ERROR in ./node_modules/preact-render-to-string/dist/index.js
    Module build failed: Error: Couldn't find preset "es2015" relative to directory "/Users/me/dev/app/node_modules/preact-render-to-string"

Render KML

I want to render KML using this, but I'm running into problems.

I have something like this

const folder = props => (
  <Folder>
    {props.children}
  </Folder>
);

const KML = () => (
  <kml>
    <folder>
      foo
    </folder>
  </kml>
);

What I want as output:

<kml>
  <Folder>
    foo
  </Folder>
</kml>

What I get is:

  <kml>
    <folder>
      foo
    </folder>
  </kml>

I passed xml: true to renderToString.

Is there a convention in the casing of JSX tags?

Example how to connect client to server-rendered DOM?

Hi, I'm experimenting with universal rendering with Preact and I'm running into this strange issue.

I render my HTML on the server using this library. It works well.
But then, when I render to the DOM on the client, it adds the content to the existing nodes instead of replacing it.
To get around this I'm now doing this on the client:

var root = document.getElementById('app-root');
root.innerHTML = '';
render(<App />, root);

Is this the correct way or should I somehow be able to 'mount' render to the existing DOM tree? I am worried that this will give ugly flashes when my app becomes bigger.

I could not find an example of this. Is there one?

Example of client-side code taking over?

I'm currently having an issue where preact on the client-side is not taking over the DOM nodes rendered by preact-render-to-string on the server. Am I missing something or does preact not currently take over pre-rendered HTML?

On the server, the content is rendered (by Nunjucks):

<div id="header">{{headerHtml | safe}}</div>

(where headerHtml is the output of render-to-string)

On the client, I'm then doing:

render((
    <Header ... />
), document.querySelector('#header'));

And the header ends up being duplicated.

Troubles with the pakage

Hi!
Thanks for the package!
I have some problems withe the package - help me please.

I try to use to preact-render-to-string on server side to render component:

App.jsx

import { h } from 'preact';
const App = () => {
    return <h1>App</h1>;
};
export default App;

serverEntry.js

import { h } from 'preact';
import render from 'preact-render-to-string';
import App from '../common/components/App.jsx';
const serverEntry = () => {
    return render(<App />);
};
export default serverEntry;

Server.js

import serverEntry from '../../serverEntry.js';
....
html = html.replace('<div id="app"></div>', serverEntry());

In my project I use to babel-env preset with target = 'node'.
When I add preact-render-to-string package to the project and try to transpile it with webpack - it breaks with error: 'Module build failed: Error: Couldn't find preset "es2015-minimal" relative to directory "D:\Projects\app1\node_modules\preact-render-to-string"'

It strange little bit....

so I add es2015-minimal to the project and again try to transpile, but now I get another warning:

node_modules\nan
resolve failed:  { Error: Cannot find module 'caniuse-db'
    at Function.Module._resolveFilename (module.js:472:15)
    at Function.requireRelative.resolve (D:\Projects\app1\node_modules\require-relative\index.js:30:17)
    at resolve (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:26:26)
    at findAndRemove (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:83:11)
    at D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:126:13
    at Array.map (native)
    at loadPreset (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:118:29)
    at module.exports (D:\Projects\app1\node_modules\modify-babel-preset\index.js:95:19)
    at Object.<anonymous> (D:\Projects\app1\node_modules\babel-preset-es2015-minimal\index.js:5:18)
    at Module._compile (module.js:573:32)
    at Module._extensions..js (module.js:582:10)
    at Object.require.extensions.(anonymous function) [as .js] (D:\Projects\app1\node_modules\babel-register\lib\node.js:152:7)
    at Module.load (module.js:490:32)
    at tryModuleLoad (module.js:449:12)
    at Function.Module._load (module.js:441:3)
    at Module.require (module.js:500:17)
    at require (internal/module.js:20:19)
    at D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:302:17
    at Array.map (native)
    at OptionManager.resolvePresets (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:270:20)
    at OptionManager.mergePresets (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:259:10)
    at OptionManager.mergeOptions (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:244:14)
    at OptionManager.init (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:374:12)
    at File.initOptions (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\index.js:216:65)
    at new File (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\index.js:139:24)
    at Pipeline.transform (D:\Projects\app1\node_modules\babel-core\lib\transformation\pipeline.js:46:16)
    at transpile (D:\Projects\app1\node_modules\babel-loader\lib\index.js:38:20)
    at Object.module.exports (D:\Projects\app1\node_modules\babel-loader\lib\index.js:133:12)
    at LOADER_EXECUTION (D:\Projects\app1\node_modules\loader-runner\lib\LoaderRunner.js:114:14)
    at runSyncOrAsync (D:\Projects\app1\node_modules\loader-runner\lib\LoaderRunner.js:115:4) code: 'MODULE_NOT_FOUND' } caniuse-db
resolve failed:  { Error: Cannot find module 'babel-runtime'
    at Function.Module._resolveFilename (module.js:472:15)
    at Function.requireRelative.resolve (D:\Projects\app1\node_modules\require-relative\index.js:30:17)
    at resolve (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:26:26)
    at findAndRemove (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:83:11)
    at D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:126:13
    at Array.map (native)
    at loadPreset (D:\Projects\app1\node_modules\modify-babel-preset\lib\serialize.js:118:29)
    at module.exports (D:\Projects\app1\node_modules\modify-babel-preset\index.js:95:19)
    at Object.<anonymous> (D:\Projects\app1\node_modules\babel-preset-es2015-minimal\index.js:5:18)
    at Module._compile (module.js:573:32)
    at Module._extensions..js (module.js:582:10)
    at Object.require.extensions.(anonymous function) [as .js] (D:\Projects\app1\node_modules\babel-register\lib\node.js:152:7)
    at Module.load (module.js:490:32)
    at tryModuleLoad (module.js:449:12)
    at Function.Module._load (module.js:441:3)
    at Module.require (module.js:500:17)
    at require (internal/module.js:20:19)
    at D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:302:17
    at Array.map (native)
    at OptionManager.resolvePresets (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:270:20)
    at OptionManager.mergePresets (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:259:10)
    at OptionManager.mergeOptions (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:244:14)
    at OptionManager.init (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\options\option-manager.js:374:12)
    at File.initOptions (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\index.js:216:65)
    at new File (D:\Projects\app1\node_modules\babel-core\lib\transformation\file\index.js:139:24)
    at Pipeline.transform (D:\Projects\app1\node_modules\babel-core\lib\transformation\pipeline.js:46:16)
    at transpile (D:\Projects\app1\node_modules\babel-loader\lib\index.js:38:20)
    at Object.module.exports (D:\Projects\app1\node_modules\babel-loader\lib\index.js:133:12)
    at LOADER_EXECUTION (D:\Projects\app1\node_modules\loader-runner\lib\LoaderRunner.js:114:14)
    at runSyncOrAsync (D:\Projects\app1\node_modules\loader-runner\lib\LoaderRunner.js:115:4) code: 'MODULE_NOT_FOUND' } babel-runtime

What is wrong?
Thanks

P.S. you can reproduce it https://github.com/budarin/app

babel-runtime error

Currently a fresh build fails (just cloned the repo):

$ npm run -s transpile && npm run -s transpile:jsx

node_modules/nan
resolve failed for "babel-runtime": Error: Cannot find module 'babel-runtime'
resolve failed for "babel-runtime": Error: Cannot find module 'babel-runtime'
node_modules/nan
resolve failed for "babel-runtime": Error: Cannot find module 'babel-runtime'
resolve failed for "babel-runtime": Error: Cannot find module 'babel-runtime'

Edit: Changed the title, because installing it via devDependencies doesn't help.

Boolean attribute rendering differs from Preact

Hi,

Boolean attribute rendering seems to differ from Preact itself (4.8.0 at least).

For example with the JSX:
<div aria-hidden={true} />

preact: <div aria-hidden="true"></div>
preact-render-to-string: <div aria-hidden></div>

http://jsfiddle.net/28ckgyzj/1/ (see console log)

(With ARIA attributes presence doesn't indicate truth as it does with the checked attribute for example).

Thanks

dangerouslySetInnerHTML difference in renderToJsxString vs renderToString

steps to reproduce

use dangerouslySetInnerHTML with renderToJsxString

> const h = require('preact').h
> console.log(require('preact-render-to-string')(<div dangerouslySetInnerHTML={{__html:'<span>foo</span>'}} />))
<div><span>foo</span></div>
undefined
> console.log(require('preact-render-to-string/jsx')(<div dangerouslySetInnerHTML={{__html:'<span>foo</span>'}} />))
<div
  dangerouslySetInnerHTML={
    Object {
      "__html": "<span>foo</span>"
    }
  }
>
</div>
undefined

expected results

dangerouslySetInnerHTML "executed" in either render method.

actual results

dangerouslySetInnerHTML "executed" only in renderToString, but not renderToJsxString.

notes

i'm using preact-jsx-chai and would rather not use dangerouslySetInnerHTML for hardcoded html in my tests. i've tracked down the issue to this library, but feel free to tell me that it should be addressed in the other one. i didn't see a way to tell that library not to use the jsxString render function.

Does not work w/ preact-compat components

Components instantiated using React style (extends Component) and while aliasing React to point at react-compat render as [object Object]. Reason being is that components instantiated using react-compat do not have a nodename:

{ '$$typeof': Symbol(react.element),
  type:
   { [Function: Footer]
     childContextTypes: { intl: [Object], locale: [Object] },
     displayName: 'Footer',
     modulePath: '/app/components/Shared/Footer' },
  key: null,
  ref: null,
  props:
   { store:
      { dispatch: [Function],
        subscribe: [Function: subscribe],
        getState: [Function: getState],
        replaceReducer: [Function: replaceReducer] },
     intl: { [Function] cache: [Object], toString: [Function], format: [Function] },
     locale: 'en-CA',
     dispatch: [Function] },
  _owner: null }

Resulting in the following code being triggered in renderToString:

if (!nodeName) {
    return encodeEntities(vnode);
}

browserify: bundling with preact/compat duplicates preact bundle

Bundling preact-render-to-string together with preact/compat results in duplicated (?) preact instead of reusing the preact/compat (if that's at all possible).

Most likely caused by peerDep being preact and not preact/compat.

Test case:

npm i browserify preact@latest preact-render-to-string@latest
  1. bundling with base preact โ†’ size 12642

    const Browserify = require("browserify");
    const { Readable, Writable } = require("stream");
    
    let len = 0;
    
    Browserify(new Readable({
        read () {
            this.push(`
                require("preact");
                require("preact-render-to-string");
            `);
            this.push(null);
        }
    }))
    .bundle()
    .pipe(new Writable({
        write (chunk, enc, next) {
            len += chunk.toString().length;
            next();
        }
    }))
    .on("finish", () => console.log("size:", len));
  2. bundling with preact/compat โ†’ size 19721

    const Browserify = require("browserify");
    const { Readable, Writable } = require("stream");
    
    let len = 0;
    
    Browserify(new Readable({
        read () {
            this.push(`
                require("preact/compat");
                require("preact-render-to-string");
            `);
            this.push(null);
        }
    }))
    .bundle()
    .pipe(new Writable({
        write (chunk, enc, next) {
            len += chunk.toString().length;
            next();
        }
    }))
    .on("finish", () => console.log("size:", len));

Fails when using hooks

The current hooks implementation rely on vnodes having a _component property. The property is created during rendering and is passed to the hooks implementation by options.render (used to be options.beforeRender).

Preact-render-to-string does not store the _component property, nor does it offer a way to pass it to the hooks implementation.

As a result preact-render-to-string fails when rendering components with hooks:

TypeError: Cannot read property '__H' of undefined
    at f (.../node_modules/preact/hooks/dist/hooks.js:1:369)
    at c (.../node_modules/preact/hooks/dist/hooks.js:1:465)
    at exports.useState (.../node_modules/preact/hooks/dist/hooks.js:1:1235)
    at HooksComponent (...)
    at s (.../node_modules/preact-render-to-string/dist/index.js:1:1470)

3.8.0 is a breaking change for components without nodenames

Our builds are failing because preact-jsx-chai is using preact-render-to-string with a ^3.x dependency. With the change in 3.8.0 to no longer cooerce node names to a String before calling the match function here 46e72e9#diff-1fdf421c05c1140f6d71444ea2b27638L162, any node that does not have a node name now fails the unit test with an exception like:

   PhantomJS 2.1.1 (Mac OS X 0.0.0)
    undefined is not an object (evaluating 'y.match')
    p@webpack:///~/preact-render-to-string/dist/jsx.js:1:2667 <- setup-unit.js:4350:141
    p@webpack:///~/preact-render-to-string/dist/jsx.js:1:1643 <- setup-unit.js:4326:34
    p@webpack:///~/preact-render-to-string/dist/jsx.js:1:1643 <- setup-unit.js:4326:34
    exports@webpack:///~/preact-render-to-string/dist/jsx.js:1:8303 <- setup-unit.js:4455:11
    doRender@webpack:///~/preact-jsx-chai/dist/index.js:65:0 <- setup-unit.js:4039:50
    webpack:///~/preact-jsx-chai/dist/index.js:80:0 <- setup-unit.js:4054:25
    /Users/bneff/repos/sports-widget/node_modules/chai/chai.js:5341:38
    webpack:///tests/unit/components/scoreboard/event.js:311:39 <- unit/components/scoreboard/event.js:7005:57

I would recommend adding the cooercion back in to a 3.8.1 release and removing it in a 4.0 release if you really want to take it out.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.