Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include definitions in node package #1287

Merged
merged 4 commits into from
Jun 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ for details.
[PR 1271](https://github.com/shakacode/react_on_rails/pull/1271) by [ashgaliyev](https://github.com/ashgaliyev).

#### Improved
- Added Typescript definitions to the Node package. By [justin808](https://github.com/justin808) and [judahmeek](https://github.com/judahmeek) in [PR 1287](https://github.com/shakacode/react_on_rails/pull/1287).
- Removed unnecessary restriction to keep the server bundle in the same directory with the client bundles. Rails/webpacker 4 has an advanced cleanup that will remove any files in the directory of other webpack files. Removing this restriction allows the server bundle to be created in a sibling directory. By [justin808](https://github.com/shakacode/react_on_rails/pull/1240).

### [11.3.0] - 2019-05-24
Expand Down
1 change: 1 addition & 0 deletions lib/react_on_rails/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ def json_safe_and_pretty(hash_or_string)
#
# rubocop:disable Metrics/AbcSize
def rails_context(server_side: true)
# ALERT: Keep in sync with node_package/src/types/index.ts for the properties of RailsContext
@rails_context ||= begin
result = {
railsEnv: Rails.env,
Expand Down
48 changes: 29 additions & 19 deletions node_package/src/clientStartup.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import ReactDOM from 'react-dom';
import type { ReactElement } from 'react';
import type {
ReactOnRails as ReactOnRailsType,
RailsContext,
ReactOnRails as ReactOnRailsType,
RegisteredComponent,
RenderFunction,
} from './types/index';
Expand Down Expand Up @@ -58,24 +58,17 @@ function turbolinksInstalled(): boolean {
return (typeof Turbolinks !== 'undefined');
}

function forEach(fn: (element: Element, railsContext: RailsContext) => void, className: string, railsContext: RailsContext): void {
const els = document.getElementsByClassName(className);
for (let i = 0; i < els.length; i += 1) {
fn(els[i], railsContext);
}
function reactOnRailsHtmlElements() {
return document.getElementsByClassName('js-react-on-rails-component');
}

function forEachByAttribute(fn: (element: Element, railsContext: RailsContext) => void, attributeName: string, railsContext: RailsContext): void {
const els = document.querySelectorAll(`[${attributeName}]`);
function forEachReactOnRailsComponentInitialize(fn: (element: Element, railsContext: RailsContext) => void, railsContext: RailsContext): void {
const els = reactOnRailsHtmlElements();
for (let i = 0; i < els.length; i += 1) {
fn(els[i], railsContext);
}
}

function forEachComponent(fn: (element: Element, railsContext: RailsContext) => void, railsContext: RailsContext = {}): void {
forEach(fn, 'js-react-on-rails-component', railsContext);
}

function initializeStore(el: Element, railsContext: RailsContext): void {
const context = findContext();
const name = el.getAttribute(REACT_ON_RAILS_STORE_ATTRIBUTE) || "";
Expand All @@ -86,7 +79,10 @@ function initializeStore(el: Element, railsContext: RailsContext): void {
}

function forEachStore(railsContext: RailsContext): void {
forEachByAttribute(initializeStore, REACT_ON_RAILS_STORE_ATTRIBUTE, railsContext);
const els = document.querySelectorAll(`[${REACT_ON_RAILS_STORE_ATTRIBUTE}]`);
for (let i = 0; i < els.length; i += 1) {
initializeStore(els[i], railsContext);
}
}

function turbolinksVersion5(): boolean {
Expand Down Expand Up @@ -174,20 +170,31 @@ You should return a React.Component always for the client side entry point.`);
}
}

function parseRailsContext(): RailsContext {
function parseRailsContext(): RailsContext | null {
const el = document.getElementById('js-react-on-rails-context');
if (el) {
return (el.textContent !== null) ? JSON.parse(el.textContent) : {};
if (!el) {
// The HTML page will not have an element with ID 'js-react-on-rails-context' if there are no
// react on rails components
return null;
}

if (!el.textContent) {
throw new Error("The HTML element with ID 'js-react-on-rails-context' has no textContent");
}
return {};

return JSON.parse(el.textContent);
}

export function reactOnRailsPageLoaded(): void {
debugTurbolinks('reactOnRailsPageLoaded');

const railsContext = parseRailsContext();

// If no react on rails components
if (!railsContext) return;

forEachStore(railsContext);
forEachComponent(render, railsContext);
forEachReactOnRailsComponentInitialize(render, railsContext);
}

function unmount(el: Element): void {
Expand All @@ -204,7 +211,10 @@ function unmount(el: Element): void {

function reactOnRailsPageUnloaded(): void {
debugTurbolinks('reactOnRailsPageUnloaded');
forEachComponent(unmount);
const els = reactOnRailsHtmlElements();
for (let i = 0; i < els.length; i += 1) {
unmount(els[i]);
}
}

function renderInit(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,24 @@ export interface CreateParams extends Params {
shouldHydrate?: boolean;
}

// Keep these in sync with method lib/react_on_rails/helper.rb#rails_context
export interface RailsContext {
railsEnv?: "development" | "test" | "staging" | "production";
inMailer?: boolean;
i18nLocale?: string;
i18nDefaultLocale?: string;
rorVersion?: string;
rorPro?: boolean;
serverSide?: boolean;
originalUrl?: string;
href?: string;
location?: string;
scheme?: string;
host?: string;
port?: string;
pathname?: string;
search?: string;
httpAcceptLanguage?: string;
railsEnv: string;
inMailer: boolean;
i18nLocale: string;
i18nDefaultLocale: string;
rorVersion: string;
rorPro: boolean;
serverSide: boolean;
originalUrl: string;
href: string;
location: string;
scheme: string;
host: string;
port: string;
pathname: string;
search: string;
httpAcceptLanguage: string;
}

type AuthenticityHeaders = {[id: string]: string} & {'X-CSRF-Token': string | null; 'X-Requested-With': string};
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@
"clean": "rm -rf node_package/lib",
"start": "nps",
"prepare": "yarn run build",
"prepublish": "npm run prepare",
"build": "yarn run clean && yarn run tsc",
"build": "yarn run clean && yarn run tsc --declaration",
"build-watch": "yarn run clean && yarn run tsc --watch",
"lint": "nps eslint",
"check": "yarn run lint && yarn run test && yarn run type-check",
Expand Down