Socket
Socket
Sign inDemoInstall

@shopify/react-html

Package Overview
Dependencies
Maintainers
12
Versions
191
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shopify/react-html - npm Package Compare versions

Comparing version 7.1.2 to 8.0.0-beta.1

dist/hook.d.ts

6

CHANGELOG.md

@@ -13,8 +13,2 @@ # Changelog

## 7.1.2 - 2019-03-02
### Fixed
- Removed the `title` and `favicon` props from `<Html />` because they did not have any effect on the rendered markup. Developers should include `<Title />` and `<Favicon />` components themselves instead.
## 7.1.1 - 2019-02-27

@@ -21,0 +15,0 @@

export * from './components';
export { default as Manager, EFFECT_ID } from './manager';
export { Provider } from './context';
export { HtmlContext, HtmlProvider } from './context';
export { showPage, getSerialized } from './utilities';
export { createSerializer } from './serializer';
export { useDomEffect } from './hook';
export { createSerializer, useSerialized } from './serializer';

6

dist/common.js

@@ -9,7 +9,11 @@ "use strict";

var context_1 = require("./context");
exports.Provider = context_1.Provider;
exports.HtmlContext = context_1.HtmlContext;
exports.HtmlProvider = context_1.HtmlProvider;
var utilities_1 = require("./utilities");
exports.showPage = utilities_1.showPage;
exports.getSerialized = utilities_1.getSerialized;
var hook_1 = require("./hook");
exports.useDomEffect = hook_1.useDomEffect;
var serializer_1 = require("./serializer");
exports.createSerializer = serializer_1.createSerializer;
exports.useSerialized = serializer_1.useSerialized;
import * as React from 'react';
declare type Props = React.HTMLProps<HTMLLinkElement>;
export default function Link(props: Props): JSX.Element;
export default function Link(props: Props): null;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var DomEffect_1 = tslib_1.__importDefault(require("./DomEffect"));
var hook_1 = require("../hook");
function Link(props) {
return (React.createElement(DomEffect_1.default, { key: JSON.stringify(props), perform: function (manager) { return manager.addLink(props); } }));
hook_1.useDomEffect(function (manager) { return manager.addLink(props); }, [JSON.stringify(props)]);
return null;
}
exports.default = Link;
import * as React from 'react';
declare type Props = React.HTMLProps<HTMLMetaElement>;
export default function Meta(props: Props): JSX.Element;
export default function Meta(props: Props): null;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var DomEffect_1 = tslib_1.__importDefault(require("./DomEffect"));
var hook_1 = require("../hook");
function Meta(props) {
return (React.createElement(DomEffect_1.default, { key: JSON.stringify(props), perform: function (manager) { return manager.addMeta(props); } }));
hook_1.useDomEffect(function (manager) { return manager.addMeta(props); }, [JSON.stringify(props)]);
return null;
}
exports.default = Meta;

@@ -8,4 +8,4 @@ "use strict";

function mountWithManager(element, manager) {
return enzyme_1.mount(React.createElement(context_1.Provider, { manager: manager }, element));
return enzyme_1.mount(React.createElement(context_1.HtmlProvider, { manager: manager }, element));
}
exports.mountWithManager = mountWithManager;

@@ -1,6 +0,5 @@

/// <reference types="react" />
interface Props {
children: string;
}
export default function Title({ children: title }: Props): JSX.Element;
export default function Title({ children: title }: Props): null;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var DomEffect_1 = tslib_1.__importDefault(require("./DomEffect"));
var hook_1 = require("../hook");
function Title(_a) {
var title = _a.children;
return React.createElement(DomEffect_1.default, { key: title, perform: function (manager) { return manager.addTitle(title); } });
hook_1.useDomEffect(function (manager) { return manager.addTitle(title); }, [title]);
return null;
}
exports.default = Title;
import * as React from 'react';
import Manager from './manager';
declare const Context: React.Context<Manager>;
export declare const HtmlContext: React.Context<Manager | undefined>;
interface Props {

@@ -8,7 +8,3 @@ manager?: Manager;

}
declare class HtmlManagerProvider extends React.Component<Props> {
private queuedUpdate?;
componentDidMount(): void;
render(): JSX.Element;
}
export { HtmlManagerProvider as Provider, Context };
export declare function HtmlProvider({ manager, children }: Props): JSX.Element;
export {};

@@ -5,33 +5,24 @@ "use strict";

var React = tslib_1.__importStar(require("react"));
var manager_1 = tslib_1.__importDefault(require("./manager"));
var utilities_1 = require("./utilities");
var Context = React.createContext(new manager_1.default());
exports.Context = Context;
var HtmlManagerProvider = /** @class */ (function (_super) {
tslib_1.__extends(HtmlManagerProvider, _super);
function HtmlManagerProvider() {
return _super !== null && _super.apply(this, arguments) || this;
}
HtmlManagerProvider.prototype.componentDidMount = function () {
var _this = this;
var manager = this.props.manager;
if (manager) {
manager.subscribe(function (state) {
if (_this.queuedUpdate) {
cancelAnimationFrame(_this.queuedUpdate);
}
_this.queuedUpdate = requestAnimationFrame(function () {
updateOnClient(state);
_this.queuedUpdate = undefined;
});
exports.HtmlContext = React.createContext(undefined);
function HtmlProvider(_a) {
var manager = _a.manager, children = _a.children;
var queuedUpdate = React.useRef(null);
React.useEffect(function () {
if (manager == null) {
return;
}
// eslint-disable-next-line consistent-return
return manager.subscribe(function (state) {
if (queuedUpdate.current) {
cancelAnimationFrame(queuedUpdate.current);
}
queuedUpdate.current = requestAnimationFrame(function () {
updateOnClient(state);
});
}
};
HtmlManagerProvider.prototype.render = function () {
var _a = this.props, manager = _a.manager, children = _a.children;
return manager ? (React.createElement(Context.Provider, { value: manager }, children)) : (React.createElement(React.Fragment, null, children));
};
return HtmlManagerProvider;
}(React.Component));
exports.Provider = HtmlManagerProvider;
});
}, [manager]);
return (React.createElement(exports.HtmlContext.Provider, { value: manager }, children));
}
exports.HtmlProvider = HtmlProvider;
function updateOnClient(state) {

@@ -38,0 +29,0 @@ var e_1, _a, e_2, _b, e_3, _c, e_4, _d;

@@ -27,3 +27,3 @@ /// <reference types="react" />

}): void;
subscribe(subscription: Subscription): void;
subscribe(subscription: Subscription): () => void;
addTitle(title: string): any;

@@ -30,0 +30,0 @@ addMeta(meta: React.HTMLProps<HTMLMetaElement>): any;

@@ -44,3 +44,7 @@ "use strict";

Manager.prototype.subscribe = function (subscription) {
var _this = this;
this.subscriptions.add(subscription);
return function () {
_this.subscriptions.delete(subscription);
};
};

@@ -47,0 +51,0 @@ Manager.prototype.addTitle = function (title) {

import * as React from 'react';
export declare const EXTRACT_ID: unique symbol;
interface SerializeProps<T> {
data(): T | Promise<T>;
data: () => T | Promise<T>;
}
interface WithSerializedProps<T> {
children(data?: T): React.ReactNode;
children(data?: T): React.ReactElement<any>;
}
export declare function useSerialized<T>(id: string): [T | undefined, React.ComponentType<SerializeProps<T>>];
export declare function createSerializer<T>(id: string): {
Serialize: ({ data }: SerializeProps<T>) => JSX.Element;
WithSerialized: ({ children }: WithSerializedProps<T>) => JSX.Element;
Serialize: ({ data }: SerializeProps<T>) => null;
WithSerialized: ({ children }: WithSerializedProps<T>) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<any, any, any>)>;
};
export {};

@@ -8,16 +8,46 @@ "use strict";

exports.EXTRACT_ID = Symbol('serialize');
function createSerializer(id) {
function Serialize(_a) {
var data = _a.data;
return (React.createElement(context_1.Context.Consumer, null, function (manager) { return (React.createElement(react_effect_1.Effect, { kind: manager.effect, perform: function () {
function useSerialized(id) {
var manager = React.useContext(context_1.HtmlContext);
var data = React.useMemo(function () { return manager && manager.getSerialization(id); }, [
id,
manager,
]);
var Serialize = React.useMemo(function () {
return function Serialize(_a) {
var data = _a.data;
var manager = React.useContext(context_1.HtmlContext);
react_effect_1.useServerEffect(function () {
var result = data();
var handleResult = manager.setSerialization.bind(manager, id);
var handleResult = manager
? manager.setSerialization.bind(manager, id)
: noop;
return typeof result === 'object' && isPromise(result)
? result.then(handleResult)
: handleResult(result);
} })); }));
}, manager && manager.effect);
return null;
};
}, [id, manager]);
return [data, Serialize];
}
exports.useSerialized = useSerialized;
function createSerializer(id) {
function Serialize(_a) {
var data = _a.data;
var manager = React.useContext(context_1.HtmlContext);
react_effect_1.useServerEffect(function () {
var result = data();
var handleResult = manager
? manager.setSerialization.bind(manager, id)
: noop;
return typeof result === 'object' && isPromise(result)
? result.then(handleResult)
: handleResult(result);
}, manager && manager.effect);
return null;
}
function WithSerialized(_a) {
var children = _a.children;
return (React.createElement(context_1.Context.Consumer, null, function (manager) { return children(manager.getSerialization(id)); }));
var manager = React.useContext(context_1.HtmlContext);
return children(manager && manager.getSerialization(id));
}

@@ -30,1 +60,2 @@ return { Serialize: Serialize, WithSerialized: WithSerialized };

}
function noop() { }

@@ -16,3 +16,5 @@ import * as React from 'react';

bodyMarkup?: React.ReactNode;
favicon?: string;
title?: string;
}
export default function Html({ manager, children, locale, blockingScripts, scripts, styles, headMarkup, bodyMarkup, }: Props): JSX.Element;
export default function Html({ manager, children, locale, blockingScripts, scripts, styles, headMarkup, bodyMarkup, favicon, title, }: Props): JSX.Element;

@@ -10,3 +10,3 @@ "use strict";

function Html(_a) {
var manager = _a.manager, children = _a.children, _b = _a.locale, locale = _b === void 0 ? 'en' : _b, _c = _a.blockingScripts, blockingScripts = _c === void 0 ? [] : _c, _d = _a.scripts, scripts = _d === void 0 ? [] : _d, _e = _a.styles, styles = _e === void 0 ? [] : _e, _f = _a.headMarkup, headMarkup = _f === void 0 ? null : _f, _g = _a.bodyMarkup, bodyMarkup = _g === void 0 ? null : _g;
var manager = _a.manager, children = _a.children, _b = _a.locale, locale = _b === void 0 ? 'en' : _b, _c = _a.blockingScripts, blockingScripts = _c === void 0 ? [] : _c, _d = _a.scripts, scripts = _d === void 0 ? [] : _d, _e = _a.styles, styles = _e === void 0 ? [] : _e, _f = _a.headMarkup, headMarkup = _f === void 0 ? null : _f, _g = _a.bodyMarkup, bodyMarkup = _g === void 0 ? null : _g, favicon = _a.favicon, title = _a.title;
var _h;

@@ -22,3 +22,4 @@ var markup = typeof children === 'string' ? children : server_1.renderToString(children);

var managedProps = (_h = {}, _h[utilities_1.MANAGED_ATTRIBUTE] = true, _h);
var titleMarkup = extracted && extracted.title ? (React.createElement("title", tslib_1.__assign({}, managedProps), extracted.title)) : null;
var titleFallbackMarkup = title ? React.createElement(components_1.Title, null, title) : null;
var titleMarkup = extracted && extracted.title ? (React.createElement("title", tslib_1.__assign({}, managedProps), extracted.title)) : (titleFallbackMarkup);
var metaMarkup = extracted

@@ -50,8 +51,10 @@ ? extracted.metas.map(function (metaProps, index) { return (

process.env.NODE_ENV === 'development' ? { visibility: 'hidden' } : undefined;
var faviconMarkup = favicon ? React.createElement(components_1.Favicon, { source: favicon }) : null;
return (React.createElement("html", { lang: locale },
React.createElement("head", null,
React.createElement(components_1.Meta, { charSet: "utf-8" }),
React.createElement(components_1.Meta, { httpEquiv: "X-UA-Compatible", content: "IE=edge" }),
React.createElement(components_1.Meta, { name: "referrer", content: "never" }),
faviconMarkup,
titleMarkup,
React.createElement("meta", { charSet: "utf-8" }),
React.createElement("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }),
React.createElement("meta", { name: "referrer", content: "never" }),
metaMarkup,

@@ -58,0 +61,0 @@ linkMarkup,

{
"name": "@shopify/react-html",
"version": "7.1.2",
"version": "8.0.0-beta.1",
"license": "MIT",

@@ -26,3 +26,3 @@ "description": "A component to render your react app with no static HTML.",

"dependencies": {
"@shopify/react-effect": "^2.0.1",
"@shopify/react-effect": "3.0.0-beta.1",
"@shopify/react-serialize": "^1.0.12",

@@ -29,0 +29,0 @@ "@shopify/useful-types": "^1.1.2",

@@ -86,28 +86,15 @@ # `@shopify/react-html`

Some parts of your application code may have some form of state that must be rehydrated when the server-rendered page is rehydrated on the client. To do so, application code can use the `createSerializer` function exported from `@shopify/react-html`.
Some parts of your application code may have some form of state that must be rehydrated when the server-rendered page is loaded on the client. To do so, application code can use the `useSerialized` hook exported from `@shopify/react-html`.
`createSerializer()` accepts a single string argument for the identifier to use; this will help you find the serialized `script` tag if you need to debug later on. It also accepts a generic type argument for the type of the data that will be serialized/ available after deserialization.
`useSerialized()` accepts a single string argument for the identifier to use; this will help you find the serialized `script` tag if you need to debug later on. It also accepts a generic type argument for the type of the data that will be serialized/ available after deserialization.
The function returns a pair of components:
The hook returns an array where the first entry is the serialized data (or `undefined`, if it was not found), and the second entry is a component that accepts a `data` prop that is a function that returns the data to serialize (or a promise for that data).
```tsx
const {Serialize, WithSerialized} = createSerializer<string>('MyData');
> **Note:** providing a promise for the `data` prop has a catch if you are using `@shopify/react-effect` to extract the serializations in server rendering: it expects that you will only provide a promise for the serialization if it can’t be returned synchronously. If you always return a promise, `@shopify/react-effect` will assume it always needs to do another render of the tree, which will lead to an infinite loop.
// Would create components with the following types:
function Serialize({data}: {data(): string}): null;
function WithSerialized({
children,
}: {
children(data: string | undefined): React.ReactNode;
}): React.ReactNode;
```
The general pattern for using these components is to render the `WithSerialized` component as the top-most child of a component responsible for managing this state. Within the render prop, construct whatever stateful store or manager you need, using the data that was retrieved in cases where the serialization was found (on the browser, or on subsequent server renders). Finally, render the UI that depends on that stateful part, and a `Serialize` component that extracts the part that you you need to communicate between server and client.
Here is a complete example, using `@shopify/react-i18n`’s support for async translations as the data that needs to be serialized:
```tsx
import {createSerializer} from '@shopify/react-html';
import {Provider, Manager} from '@shopify/react-i18n';
import {useSerialized} from '@shopify/react-html';
import {I18nContext, Manager} from '@shopify/react-i18n';

@@ -123,24 +110,26 @@ interface Props {

interface Data {
locale: string;
translations: ReturnType<Manager['extract']>;
}
export default function I18n({locale, children}: Props) {
const [serialized, Serialize] = useSerialized<Data>('i18n');
const {locale, translations} = serialized || {locale: explicitLocale};
const manager = new Manager({locale, fallbackLocale: 'en'}, translations);
return (
<WithSerialized>
{data => {
const manager = new Manager(
{locale: data ? data.locale : locale},
data && data.translations,
);
<>
<I18nContext.Provider value={manager}>{children}</I18nContext.Provider>
<Serialize
data={() => {
const getData = () => ({
locale: manager.details.locale,
translations: manager.extract(),
});
return (
<>
<Provider manager={manager}>{children}</Provider>
<Serialize
data={() => ({
locale: manager.details.locale,
translations: manager.extract(),
})}
/>
</>
);
}}
</WithSerialized>
return manager.loading ? manager.resolve().then(getData) : getData();
}}
/>
</>
);

@@ -154,2 +143,10 @@ }

### `useSerialized()`
See the example above for a full exploration of `useSerialized`’s API.
### `createSerializer()`
`createSerializer` is a legacy API that has been deprecated by `useSerialized()`. For full documentation of this API, please refer to older versions of this document. `createSerializer` will be removed in the next major version of `@shopify/react-html`.
### `<Html />`

@@ -246,3 +243,3 @@

The Serialize component takes care of rendering a `script` tag with a serialized version of the `data` prop. It is provided for incremental adoption of the `createSerializer()` method of generating serializations [documented above](#in-your-app-code).
The Serialize component takes care of rendering a `script` tag with a serialized version of the `data` prop. It is provided for incremental adoption of the `useSerialized()` method of generating serializations [documented above](#in-your-app-code).

@@ -249,0 +246,0 @@ ### `render()`

export * from './components';
export {default as Manager, EFFECT_ID} from './manager';
export {Provider} from './context';
export {HtmlContext, HtmlProvider} from './context';
export {showPage, getSerialized} from './utilities';
export {createSerializer} from './serializer';
export {useDomEffect} from './hook';
export {createSerializer, useSerialized} from './serializer';

@@ -60,2 +60,5 @@ import {EffectKind} from '@shopify/react-effect';

this.subscriptions.add(subscription);
return () => {
this.subscriptions.delete(subscription);
};
}

@@ -62,0 +65,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc