quilt_rails 1.12.2 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bffce621674adffbbc47252a053c9a7625a3ab2cdfc0fcc5c17faa212d8dd341
4
- data.tar.gz: e722c00ae0696417402a2498b7b84ceae1be99800576865ea2e4a84af815eced
3
+ metadata.gz: dee878b6b3d7207ed8c6883791e896ccc1208d6508aae5c592487d2da900cf91
4
+ data.tar.gz: 38f3fbd9695b816b0a873891b3fd6b90377f541595ac3427b11677d62289e6aa
5
5
  SHA512:
6
- metadata.gz: b383932fe698a1f0fd19b8a08be1d463a3e38b2c3ee430d2988198d1b1c53d80ee0d6b35fcef456414d9a31557cd358170ec755c2281309a5e651594008d695d
7
- data.tar.gz: c3b05b4e3a5f0cf05bd3e37bbf2d5779f402acc23c6e5186bc46beefb0d0db9739d1cf4d80d7288e580d373c88b41f7aa2c2bf5d5f4175dc4836cfd27bee21e7
6
+ metadata.gz: 0fb1891f8f988bb0b1b8c60c7b5b25e45c8859ba06ef855625d4656fd24f54a79ead749bad2ee0a2a15559ce097106215d5801a6eda9b3b6c55b7fdc2ee42895
7
+ data.tar.gz: 74d4d5a3b5ed3e96ce4d3348c67ecc89e6022c24cf631c3be192eb43b7ca4202e4d82351d0d22fd8385ddc75c3ddc82657ca54689b35a1341b44de8b3bf70aa9
data/README.md CHANGED
@@ -8,57 +8,47 @@ A turn-key solution for integrating Quilt client-side libraries into your Rails
8
8
  - [Quick start](#quick-start)
9
9
  - [Generate Rails boilerplate](#generate-rails-boilerplate)
10
10
  - [Add Ruby dependencies](#add-ruby-dependencies)
11
- - [Generate Quilt boilerplate](#generate-quilt-boilerplate)
11
+ - [Generate app boilerplate](#generate-app-boilerplate)
12
12
  - [Try it out](#try-it-out)
13
13
  - [Manual Install](#manual-installation)
14
- - [Generate Rails boilerplate](#generate-rails-boilerplate)
15
- - [Install Dependencies](#install-dependencies)
16
- - [Setup the Rails app](#setup-the-rails-app)
17
- - [Add JavaScript](#add-javascript)
18
- - [Run the server](#run-the-server)
19
14
  - [Application Layout](#application-layout)
20
15
  - [Advanced Use](#advanced-use)
21
16
  - [Testing](#testing)
22
17
  - [Interacting with the request and response in React code](#interacting-with-the-request-and-response-in-react-code)
23
18
  - [Dealing with isomorphic state](#dealing-with-isomorphic-state)
24
- - [Customizing the node server](#customizing-the-node-server)
19
+ - [Customizing the Node server](#customizing-the-node-server)
25
20
  - [Fixing rejected CSRF tokens for new user sessions](#fixing-rejected-csrf-tokens-for-new-user-sessions)
26
21
  - [Performance tracking a React app](#performance-tracking-a-react-app)
27
- - [Install dependencies](#install-dependencies)
28
- - [Setup an endpoint for performance reports](setup-an-endpoint-for-performance-reports)
29
- - [Add annotations](#add-annotations)
30
- - [Send the report](#send-the-report)
31
- - [Verify in development](#verify-in-development)
32
- - [Configure StatsD for production](#configure-statsd-for-production)
33
22
  - [API](#api)
34
- - [ReactRenderable](#reactrenderable)
35
- - [Performance](#performance)
36
- - [Engine](#engine)
37
- - [Generators](#generators)
38
23
 
39
24
  ## Server-side-rendering
40
25
 
26
+ 🗒 This guide is focused on internal Shopify developers with access to [`dev`](https://github.com/Shopify/dev) and [@shopify/sewing-kit](https://github.com/Shopify/sewing-kit). A similar setup can be achieved using the [manual installation](./docs/manual-installation) , and following the [react-server-webpack-plugin](../../packages/react-server-webpack-plugin/README.md) guide. Apps not running on Shopify infrastructure should [disable server-side GraphQL queries](./docs/FAQ.md) to avoid scalability issue.
27
+
41
28
  ### Quick start
42
29
 
43
30
  Using the magic of generators, we can spin up a basic app with a few console commands.
44
31
 
45
32
  #### Generate Rails boilerplate
46
33
 
47
- `dev init`
48
-
34
+ With access to [`dev`](https://github.com/Shopify/dev), you can use `dev init` to scaffold out a Rails application.
49
35
  When prompted, choose `rails`. This will generate a basic Rails application scaffold.
50
36
 
37
+ Alternatively, you can use [`rails new .`](https://guides.rubyonrails.org/command_line.html#rails-new) to do the same.
38
+
39
+ In either case, remove [`webpacker`](./docs/FAQ.md#i-run-into-webpacker-issue-while-setting-up-quilt_rails) before continuing.
40
+
51
41
  #### Add Ruby dependencies
52
42
 
53
43
  `bundle add sewing_kit quilt_rails`
54
44
 
55
45
  This will install our ruby dependencies and update the project's gemfile.
56
46
 
57
- #### Generate Quilt boilerplate
47
+ #### Generate app boilerplate
58
48
 
59
- `rails generate quilt:install`
49
+ `rails generate quilt_rails:install`
60
50
 
61
- This will install the Node dependencies, provide a basic React app (in TypeScript) and mounts the Quilt engine inside of `config/routes.rb`.
51
+ This will install Node dependencies, provide a basic React app (in TypeScript), and mount the Quilt engine in `config/routes.rb`. Basic linting and format configurations are also generated.
62
52
 
63
53
  #### Try it out
64
54
 
@@ -71,173 +61,7 @@ Will run the application, starting up both servers and compiling assets.
71
61
 
72
62
  ### Manual installation
73
63
 
74
- An application can also be setup manually using the following steps.
75
-
76
- [Generate Rails boilerplate](#generate-rails-boilerplate)
77
-
78
- #### Install dependencies
79
-
80
- ```sh
81
- # Add ruby dependencies
82
- bundle add sewing_kit quilt_rails
83
-
84
- # Add core Node dependencies
85
- yarn add @shopify/sewing-kit @shopify/react-server
86
-
87
- # Add React
88
- yarn add react react-dom
89
-
90
- # Add Typescript
91
- yarn add typescript @types/react @types/react-dom
92
- ```
93
-
94
- ##### Define typescript config
95
-
96
- ```json
97
- // tsconfig.json
98
- {
99
- "extends": "@shopify/typescript-configs/application.json",
100
- "compilerOptions": {
101
- "baseUrl": ".",
102
- "rootDir": "."
103
- },
104
- "include": ["app/ui"]
105
- }
106
- ```
107
-
108
- ```sh
109
- yarn
110
- dev up
111
- ```
112
-
113
- #### Setup the Rails app
114
-
115
- There are 2 ways to consume this package.
116
-
117
- ##### Option 1: Mount the Engine
118
-
119
- Add the engine to `routes.rb`.
120
-
121
- ```ruby
122
- # config/routes.rb
123
- Rails.application.routes.draw do
124
- # ...
125
- mount Quilt::Engine, at: '/'
126
- end
127
- ```
128
-
129
- If only a sub-section of routes should respond with the React App, it can be configured using the `at` parameter.
130
-
131
- ```ruby
132
- # config/routes.rb
133
- Rails.application.routes.draw do
134
- # ...
135
- mount Quilt::Engine, at: '/path/to/react'
136
- end
137
- ```
138
-
139
- ##### Option 2: Add a React controller and routes
140
-
141
- Create a `ReactController` to handle react requests.
142
-
143
- ```ruby
144
- class ReactController < ApplicationController
145
- include Quilt::ReactRenderable
146
-
147
- def index
148
- render_react
149
- end
150
- end
151
- ```
152
-
153
- Add routes to default to the `ReactController`.
154
-
155
- ```ruby
156
- get '/*path', to: 'react#index'
157
- root 'react#index'
158
- ```
159
-
160
- #### Add JavaScript
161
-
162
- `sewing_kit` looks for the top level component of your React app in `app/ui/index`. The component exported from this component (and any imported JS/CSS) will be built into a `main` bundle, and used to render the initial server-rendered markup.
163
-
164
- We will add a basic entrypoint using React with some HTML.
165
-
166
- ```tsx
167
- // app/ui/index.tsx
168
-
169
- import React from 'react';
170
-
171
- function App() {
172
- return <h1>My application ❤️</h1>;
173
- }
174
-
175
- export default App;
176
- ```
177
-
178
- #### Run the server
179
-
180
- `dev server`
181
-
182
- Will run the application, starting up both servers and compiling assets.
183
-
184
- ### Application layout
185
-
186
- #### Minimal
187
-
188
- The basic layout for an app using `quilt_rails` and friends will have a `ui` folder nested inside the normal Rails `app` folder, containing at _least_ an index.js file exporting a React component.
189
-
190
- ```
191
- ├── Gemfile (must contain "gem 'sewing_kit" and "gem 'quilt_rails'")
192
- ├── package.json (must specify '@shopify/sewing-kit' and `@shopify/react-server` as 'dependencies')
193
-
194
- └── app
195
- └── ui
196
- │ └─- index.{js|ts} (exports a React component)
197
- └── controllers
198
- └─- react_controller.rb (see above)
199
- ```
200
-
201
- #### Rails and React
202
-
203
- A more complex application will want a more complex layout. The following shows scalable locations for:
204
-
205
- - Global SCSS settings
206
- - App sections (roughly analogous to Rails routes)
207
- - Components
208
- - Co-located CSS modules
209
- - Co-located unit tests
210
- - Test setup files
211
-
212
- ```
213
- └── app
214
- └── ui
215
- ├─- index.{js|ts} (exports a React component)
216
- ├── styles (optional)
217
- └── shared.scss (common functions/mixins you want available in every scss file. Requires configuring `plugin.sass`'s `autoInclude` option in `sewing-kit.config.js`)
218
-
219
- └── tests (optional)
220
- │ └── each-test.{js|ts}
221
- │ └── setup.{js|ts}
222
- └── features (optional)
223
- ├── App
224
- │ ├── index.{js|ts}
225
- │ ├── App.{js|ts}x
226
- │ └── tests
227
- │ └── App.test.{js|ts}x
228
-
229
- ├-─ MyComponent
230
- │ ├-─ index.{js|ts}
231
- │ ├-─ MyComponent.{js|ts}x
232
- │ ├── MyComponent.scss (optional; component-scoped CSS styles, mixins, etc)
233
- │ └── tests
234
- │ └── MyComponent.test.{js|ts}x
235
-
236
- └── sections (optional; container views that compose presentation components into UI blocks)
237
- └── Home
238
- ├-─ index.{js|ts}
239
- └── Home.{js|ts}
240
- ```
64
+ Follow [this guide](./docs/manual-installation) on how to do manual setup without the generator.
241
65
 
242
66
  ### Advanced use
243
67
 
@@ -355,30 +179,7 @@ class ReactController < ApplicationController
355
179
  end
356
180
  ```
357
181
 
358
- The React server will serialize the provided quilt data using `quilt-data` as the ID. You can then get this serialized data on the client with `getSerialized` from `@shopify/react-html`.
359
-
360
- ```tsx
361
- // app/ui/index.tsx
362
-
363
- import React from 'react';
364
- import {getSerialized} from '@shopify/react-html';
365
-
366
- const IS_CLIENT = typeof window !== 'undefined';
367
-
368
- function App() {
369
- // get the serialized data from the request that was sent through Rails ReactController
370
- const quiltData = IS_CLIENT ? getSerialized<Record<string, any>>('quilt-data') : null;
371
-
372
- // Logs {"some_id":123}
373
- console.log(quiltData);
374
-
375
- return <h1>Data: {quiltData}</h1>;
376
- }
377
-
378
- export default App;
379
- ```
380
-
381
- If using the webpack plugin, this will be done automatically and the data will be passed into your application as the `data` prop.
182
+ If using the webpack plugin, this will be automatically passed into your application as the `data` prop.
382
183
 
383
184
  ```tsx
384
185
  // app/ui/index.tsx
@@ -419,9 +220,9 @@ With SSR enabled React apps, state must be serialized on the server and deserial
419
220
 
420
221
  `useSerialized` can be used to implement [universal-providers](https://github.com/Shopify/quilt/tree/master/packages/react-universal-provider#what-is-a-universal-provider-), allowing application code to manage what is persisted between the server and client without adding any custom code to client or server entrypoints. We offer some for common use cases such as [CSRF](https://github.com/Shopify/quilt/tree/master/packages/react-csrf-universal-provider), [GraphQL](https://github.com/Shopify/quilt/tree/master/packages/react-graphql-universal-provider), [I18n](https://github.com/Shopify/quilt/tree/master/packages/react-i18n-universal-provider), and the [Shopify App Bridge](https://github.com/Shopify/quilt/tree/master/packages/react-app-bridge-universal-provider).
421
222
 
422
- #### Customizing the node server
223
+ #### Customizing the Node server
423
224
 
424
- By default, sewing-kit bundles in [`@shopify/react-server-webpack-plugin`](../../packages/react-server-webpack-plugin/README.md) for `quilt_rails` applications to get apps up and running fast without needing to manually write any node server code.
225
+ By default, sewing-kit bundles in [`@shopify/react-server-webpack-plugin`](../../packages/react-server-webpack-plugin/README.md) for `quilt_rails` applications to get apps up and running fast without needing to manually write any Node server code.
425
226
 
426
227
  If what it provides is not sufficient, a completely custom server can be defined by adding a `server.js` or `server.ts` file to the `app/ui` folder. The simplest way to customize the server is to export the object created by [`@shopify/react-server`](../../packages/react-server/README.md#node-usage)'s `createServer` call in `server.ts` file.
427
228
 
@@ -478,361 +279,13 @@ end
478
279
 
479
280
  ## Performance tracking a React app
480
281
 
481
- Using [`Quilt::Performance::Reportable`](#performanceReportable) and [@shopify/react-performance](https://www.npmjs.com/package/@shopify/react-performance) it's easy to add performance tracking to apps using[`sewing_kit`](https://github.com/Shopify/sewing-kit/tree/master/gems/sewing_kit#sewing_kit-) for client-side-rendering or `quilt_rails` for server-side-rendering.
482
-
483
- ### Install dependencies
484
-
485
- 1. Install the gem (if your app is not already using `quilt_rails`).
486
-
487
- ```bash
488
- bundle add quilt_rails
489
- ```
490
-
491
- 2. Install `@shopify/react-performance`, the library we will use to annotate our React application and send performance reports to our server.
492
-
493
- ```bash
494
- yarn add @shopify/react-performance
495
- ```
496
-
497
- ### Setup an endpoint for performance reports
498
-
499
- If your application is not using `Quilt::Engine`, you will need to manually configure the server-side portion of performance tracking. If it _is_ using the engine, the following will be done automatically.
500
-
501
- 1. Add a `PerformanceController` and the corresponding routes to your Rails app.
502
-
503
- ```ruby
504
- # app/controllers/performance_report_controller.rb
505
-
506
- class PerformanceReportController < ActionController::Base
507
- include Quilt::Performance::Reportable
508
- protect_from_forgery with: :null_session
509
-
510
- def create
511
- process_report
512
-
513
- render(json: { result: 'success' }, status: 200)
514
- rescue ActionController::ParameterMissing => error
515
- render(json: { error: error.message }, status: 422)
516
- end
517
- end
518
- ```
519
-
520
- 2. Add a route pointing at the controller.
521
-
522
- ```ruby
523
- # config/routes.rb
524
-
525
- post '/performance_report', to: 'performance_report#create'
526
-
527
- # rest of routes
528
- ```
529
-
530
- ### Add annotations
531
-
532
- Add a [`usePerformanceMark`](https://github.com/Shopify/quilt/tree/master/packages/react-performance#useperformancemark) call to each of your route-level components.
533
-
534
- ```tsx
535
- // app/ui/features/Home/Home.tsx
536
- import {usePerformanceMark} from '@shopify/react-performance';
537
-
538
- export function Home() {
539
- // tell the library the page has finished rendering completely
540
- usePerformanceMark('complete', 'Home');
541
-
542
- return <>{/* your Home page JSX goes here*/}</>;
543
- }
544
- ```
545
-
546
- ### Send the report
547
-
548
- Add a [`usePerformanceReport`](https://github.com/Shopify/quilt/tree/master/packages/react-performance#usePerformanceReport) call to your top-level `<App />` component.
549
-
550
- ```tsx
551
- // app/ui/foundation/App/App.tsx
552
- import {usePerformanceReport} from '@shopify/react-performance';
553
-
554
- export function App() {
555
- // send the report to the server
556
- usePerformanceReport('/performance_report');
557
-
558
- return <>{/* your app JSX goes here*/}</>;
559
- }
560
- ```
561
-
562
- For more details on how to use the APIs from `@shopify/react-performance` check out its [documentation](https://github.com/Shopify/quilt/tree/master/packages/react-performance).
563
-
564
- ### Verify in development
565
-
566
- By default `quilt_rails` will not send metrics in development mode. To verify your app is setup correctly you can check in your network tab when visiting your application and see that POST requests are sent to `/performance_report`, and recieve a `200 OK` response.
567
-
568
- If you want more insight into what distributions _would_ be sent in production, you can use the `on_distribution` callback provided by the library to setup logging.
569
-
570
- ```ruby
571
- # app/controllers/performance_report_controller.rb
572
-
573
- class PerformanceReportController < ActionController::Base
574
- include Quilt::Performance::Reportable
575
- protect_from_forgery with: :null_session
576
-
577
- def create
578
- # customize process_report's behaviour with a block
579
- process_report do |client|
580
- client.on_distribution do |name, value, tags|
581
- # We log out the details of each distribution that would be sent in production.
582
- Rails.logger.debug("Distribution: #{name}, #{value}, #{tags}")
583
- end
584
- end
585
-
586
- render json: { result: 'success' }, status: 200
587
- rescue ActionController::ParameterMissing => error
588
- render json: { error: error.message, status: 422 }
589
- end
590
- end
591
- ```
592
-
593
- Now you can check your Rails console output and verify that metrics are reported as expected.
594
-
595
- ### Configure StatsD for production
596
-
597
- > Attention Shopifolk! If using `dev` your `StatsD` endpoint will already be configured for you in production. You should not need to do the following. ✨
598
-
599
- To tell `Quilt::Performance::Reportable` where to send it's distributions, setup the environment variables detailed [documentation](https://github.com/Shopify/statsd-instrument#configuration).
282
+ To setup performance tracking with your React app with `quilt_rails`.
283
+ Follow details guide [here](./docs/performance-tracking).
600
284
 
601
285
  ## API
602
286
 
603
- ### ReactRenderable
604
-
605
- The `ReactRenderable` mixin is intended to be used in Rails controllers, and provides only the `render_react` method. This method handles proxying to a running `@shopify/react-server`.
606
-
607
- ```ruby
608
- class ReactController < ApplicationController
609
- include Quilt::ReactRenderable
610
-
611
- def index
612
- render_react
613
- end
614
- end
615
- ```
616
-
617
- ### Performance
618
-
619
- #### Reportable
620
-
621
- The `Quilt::Performance::Reportable` mixin is intended to be used in Rails controllers, and provides only the `process_report` method. This method handles parsing an incoming report from [@shopify/react-performance's](https://www.npmjs.com/package/@shopify/react-performance) `<PerformanceReport />` component (or a custom report in the same format) and sending it to your application's StatsD endpoint as `distribution`s using [`StatsD-Instrument`](https://rubygems.org/gems/statsd-instrument).
622
-
623
- > **Note** `Quilt::Performance::Reportable` does not require you to use the `React::Renderable` mixin, React-Server, or even any server-side-rendering solution at all. It should work perfectly fine for applications using something like `sewing_kit_script_tag` based client-side-rendering.
624
-
625
- ```ruby
626
- class PerformanceController < ApplicationController
627
- include Quilt::Performance::Reportable
628
-
629
- def create
630
- process_report
631
- end
632
- end
633
- ```
634
-
635
- The params sent to the controller are expected to be of type `application/json`. Given the following example JSON sent by `@shopify/react-performance`,
636
-
637
- ```json
638
- {
639
- "connection": {
640
- "rtt": 100,
641
- "downlink": 2,
642
- "effectiveType": "3g",
643
- "type": "4g"
644
- },
645
- "navigations": [
646
- {
647
- "details": {
648
- "start": 12312312,
649
- "duration": 23924,
650
- "target": "/",
651
- "events": [
652
- {
653
- "type": "script",
654
- "start": 23123,
655
- "duration": 124
656
- },
657
- {
658
- "type": "style",
659
- "start": 23,
660
- "duration": 14
661
- }
662
- ],
663
- "result": 0
664
- },
665
- "metadata": {
666
- "index": 0,
667
- "supportsDetailedTime": true,
668
- "supportsDetailedEvents": true
669
- }
670
- }
671
- ],
672
- "events": [
673
- {
674
- "type": "ttfb",
675
- "start": 2,
676
- "duration": 1000
677
- }
678
- ]
679
- }
680
- ```
681
-
682
- given the the above controller input, the library would send the following metrics:
683
-
684
- ```ruby
685
- StatsD.distribution('time_to_first_byte', 2, tags: {
686
- browser_connection_type:'3g',
687
- })
688
- StatsD.distribution('time_to_first_byte', 2, tags: {
689
- browser_connection_type:'3g' ,
690
- })
691
- StatsD.distribution('navigation_complete', 23924, tags: {
692
- browser_connection_type:'3g' ,
693
- })
694
- StatsD.distribution('navigation_usable', 23924, tags: {
695
- browser_connection_type:'3g' ,
696
- })
697
- ```
698
-
699
- ##### Default Metrics
700
-
701
- The full list of metrics sent by default are as follows:
702
-
703
- ###### For full-page load
704
-
705
- - `AppName.time_to_first_byte`, representing the time from the start of the request to when the server began responding with data.
706
- - `AppName.time_to_first_paint`, representing the time from the start of the request to when the browser rendered anything to the screen.
707
- - `AppName.time_to_first_contentful_paint` representing the time from the start of the request to when the browser rendered meaningful content to the screen.
708
- - `AppName.dom_content_loaded` representing the time from the start of the request to when the browser fired the [DOMContentLoaded](https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event) event.
709
- - `AppName.dom_load` representing the time from the start of the request to when the browser fired the [window.load](https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event) event.
710
-
711
- ###### For both full-page navigations and client-side page transitions
712
-
713
- - `AppName.navigation_usable`, representing the time it took before for the page to be rendered in a usable state. Usually this does not include data fetching or asynchronous tasks.
714
- - `AppName.navigation_complete` representing the time it took for the page to be fully loaded, including any data fetching which blocks above-the-fold content.
715
- - `AppName.navigation_download_size`, representing the total weight of all client-side assets (eg. CSS, JS, images). This will only be sent if there are any events with a `type` of `script` or `style`.
716
- - `AppName.navigation_cache_effectiveness`, representing what percentage of client-side assets (eg. CSS, JS, images) were returned from the browser's cache. This will only be sent if there are any events with a `type` of `script` or `style`.
717
-
718
- ##### Customizing `process_report` with a block
719
-
720
- The behaviour of `process_report` can be customized by manipulating the `Quilt::Performance::Client` instance yielded into its implicit block parameter.
721
-
722
- ```ruby
723
- process_report do |client|
724
- # client.on_distribution do ....
725
- end
726
- ```
727
-
728
- #### Client
729
-
730
- The `Quilt::Performance::Client` class is yielded into the block parameter for `process_report`, and is the primary API for customizing what metrics are sent for a given POST.
731
-
732
- ##### Client#on_distribution
733
-
734
- The `on_distribution` method takes a block which is run for each distribution (including custom ones) sent during `process_report`.
735
-
736
- The provided callback can be used to easily add logging or other side-effects to your measurements.
737
-
738
- ```ruby
739
- client.on_distribution do |metric_name, value, tags|
740
- Rails.logger.debug "#{metric_name}: #{value}, tags: #{tags}"
741
- end
742
- ```
743
-
744
- ##### Client#on_navigation
745
-
746
- The `on_navigation` method takes a block which is run once per navigation reported to the performance controller _before_ the default distributions for the navigation are sent.
747
-
748
- The provided callback can be used to add tags to the default `distributions` for a given navigation.
749
-
750
- ```ruby
751
- client.on_navigation do |navigation, tags|
752
- # add tags to be sent with each distribution for this navigation
753
- tags[:connection_rtt] = navigation.connection.rtt
754
- tags[:connection_type] = navigation.connection.type
755
- tags[:navigation_target] = navigation.target
756
-
757
- # add a tag to allow filtering out navigations that are too long
758
- # this is useful when you are unable to rule out missing performance marks on some pages
759
- tags[:too_long_dont_read] = navigation.duration > 30.seconds.in_milliseconds
760
- end
761
- ```
762
-
763
- It can also be used to compute and send entirely custom metrics.
764
-
765
- ```ruby
766
- client.on_navigation do |navigation, tags|
767
- # calculate and then send an additional distribution
768
- weight = navigation.events_with_size.reduce(0) do |total, event|
769
- total + event.size
770
- end
771
- client.distribution('navigation_total_resource_weight', weight, tags)
772
- end
773
- ```
774
-
775
- ##### Client#on_event
776
-
777
- The `on_event` method takes a block which is run once per event reported to the performance controller _before_ the default distributions for the event are sent.
778
-
779
- The provided callback can be used to add tags to the default `distributions` for a given event, or perform other side-effects.
780
-
781
- ```ruby
782
- client.on_event do |event, tags|
783
- # add tags to be sent with each distribution for this event
784
- tags[:connection_rtt] = event.connection.rtt
785
- tags[:connection_type] = event.connection.type
786
- end
787
- ```
788
-
789
- ### Engine
790
-
791
- `Quilt::Engine` provides:
792
-
793
- - a preconfigured `UiController` which consumes `ReactRenderable`
794
- - a preconfigured `PerformanceReportController` which consumes `Performance::Reportable`
795
- - a `/performance_report` route mapped to `performance_report#index`
796
- - a catch-all index route mapped to the `UiController#index`
797
-
798
- ```ruby
799
- # config/routes.rb
800
- Rails.application.routes.draw do
801
- # ...
802
- mount Quilt::Engine, at: '/my-front-end'
803
- end
804
- ```
805
-
806
- The above is the equivalent of
807
-
808
- ```ruby
809
- post '/my-front-end/performance_report', to: 'performance_report#create'
810
- get '/my-front-end/*path', to: 'ui#index'
811
- get '/my-front-end', to: 'ui#index'
812
- ```
813
-
814
- ### Configuration
815
-
816
- The `configure` method allows customization of the address the service will proxy to for UI rendering.
817
-
818
- ```ruby
819
- # config/initializers/quilt.rb
820
- Quilt.configure do |config|
821
- config.react_server_host = "localhost:3000"
822
- config.react_server_protocol = 'https'
823
- end
824
- ```
825
-
826
- ### StatsD environment variables
827
-
828
- The `Performance::Reportable` mixin uses [https://github.com/Shopify/statsd-instrument](StatsD-Instrument) to send distributions. For detailed instructions on configuring where it sends data see [the documentation](https://github.com/Shopify/statsd-instrument#configuration).
829
-
830
- ### Generators
831
-
832
- #### `quilt:install`
833
-
834
- Installs the Node dependencies, provide a basic React app (in TypeScript) and mounts the Quilt engine in `config/routes.rb`.
287
+ Find all features this gem offer in this [API doc](./docs/api).
835
288
 
836
- #### `sewing_kit:install`
289
+ ## FAQ
837
290
 
838
- Adds a basic `sewing-kit.config.ts` file.
291
+ Find your [here](./docs/FAQ).
@@ -2,52 +2,10 @@
2
2
 
3
3
  module Quilt
4
4
  class InstallGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- desc "This generator mounts the Quilt engine and adds a React app."
8
-
9
- def install_js_dependencies
10
- say "Installing @shopify/react-server and @shopify/sewing-kit dependencies"
11
- system("yarn add "\
12
- "@shopify/sewing-kit "\
13
- "@shopify/react-server "\
14
- "typescript "\
15
- "react "\
16
- "react-dom "\
17
- "@types/react "\
18
- "@types/react-dom") unless Rails.env.test?
19
- end
20
-
21
- def create_tsconfig
22
- tsconfig_path = "tsconfig.json"
23
-
24
- unless File.exist?(tsconfig_path)
25
- copy_file "tsconfig.json", tsconfig_path
26
-
27
- log(tsconfig_path, 'wrote')
28
- end
29
- end
30
-
31
- def create_app_file
32
- app_path = "app/ui/index.tsx"
33
-
34
- unless File.exist?(app_path)
35
- copy_file "App.tsx", app_path
36
-
37
- log("React App at #{app_path}", 'wrote')
38
- end
39
- end
40
-
41
- def create_route_file
42
- routes_path = "config/routes.rb"
43
-
44
- if File.exist?(routes_path)
45
- route "mount Quilt::Engine, at: '/'"
46
- else
47
- copy_file "routes.rb", routes_path
48
- end
49
-
50
- say "Added Quilt engine mount"
5
+ def run_all_generators
6
+ generate("quilt:rails_setup")
7
+ generate("quilt:react_setup")
8
+ generate("quilt:react_app")
51
9
  end
52
10
  end
53
11
  end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ This generator mounts the Quilt engine.
3
+
4
+ Example:
5
+ rails generate quilt:rails_setup
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quilt
4
+ class RailsSetupGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ desc "This generator mounts the Quilt engine and add Procfile."
8
+
9
+ def create_procfile_entry
10
+ procfile_path = "Procfile"
11
+
12
+ if File.exist?(procfile_path)
13
+ append_file(procfile_path, File.read(File.expand_path(find_in_source_paths(procfile_path))))
14
+ else
15
+ copy_file procfile_path
16
+ end
17
+ end
18
+
19
+ def create_route_file
20
+ routes_path = "config/routes.rb"
21
+
22
+ if File.exist?(routes_path)
23
+ route "mount Quilt::Engine, at: '/'"
24
+ else
25
+ copy_file "routes.rb", routes_path
26
+ end
27
+
28
+ say "Added Quilt engine mount"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,2 @@
1
+ node: node build/server/main.js
2
+ web: bundle exec rails server -p $PORT -e $RAILS_ENV
@@ -0,0 +1,5 @@
1
+ Description:
2
+ This generator adds a React app.
3
+
4
+ Example:
5
+ rails generate quilt:react_app
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quilt
4
+ class ReactAppGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ desc "This generator adds a React app."
8
+
9
+ def create_app_file
10
+ copy_file("App.tsx", "app/ui/index.tsx")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ This generator adds Node dependencies necessary for a React app.
3
+
4
+ Example:
5
+ rails generate quilt:react_setup
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quilt
4
+ class ReactSetupGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ desc "This generator adds a React app."
8
+
9
+ def install_js_dependencies
10
+ say "Installing @shopify/react-server and @shopify/sewing-kit dependencies"
11
+ system("yarn add "\
12
+ "@shopify/sewing-kit "\
13
+ "@shopify/react-server "\
14
+ "typescript@~3.8.0 "\
15
+ "react@~16.11.0 "\
16
+ "react-dom@~16.11.0 "\
17
+ "@types/react@~16.9.0 "\
18
+ "@types/react-dom@~16.9.0 ") unless Rails.env.test?
19
+ end
20
+
21
+ def create_tsconfig
22
+ copy_file("tsconfig.json")
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+
3
+ function App() {
4
+ return <div>Hello Quilt</div>;
5
+ }
6
+
7
+ export default App;
@@ -2,7 +2,10 @@
2
2
  "extends": "@shopify/typescript-configs/application.json",
3
3
  "compilerOptions": {
4
4
  "baseUrl": ".",
5
- "rootDir": "."
5
+ "rootDir": ".",
6
+ "paths": {
7
+ "*": ["app/ui/*"]
8
+ }
6
9
  },
7
- "include": ["app/ui"]
10
+ "include": ["./config/*.ts", "./app/ui/**/*"]
8
11
  }
@@ -0,0 +1,5 @@
1
+ Description:
2
+ This generator runs all the generators
3
+
4
+ Example:
5
+ rails generate quilt_rails:install
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuiltRails
4
+ class InstallGenerator < Rails::Generators::Base
5
+ def run_all_generators
6
+ generate("sewing_kit:install")
7
+ generate("quilt:install")
8
+ end
9
+ end
10
+ end
@@ -2,4 +2,4 @@ Description:
2
2
  This generator creates a sewing-kit config file.
3
3
 
4
4
  Example:
5
- rails generate sewing-kit:install
5
+ rails generate sewing_kit:install
@@ -6,16 +6,29 @@ module SewingKit
6
6
 
7
7
  desc "This generator creates a sewing-kit config file."
8
8
 
9
- def create_config
10
- config_path = "config/sewing-kit.config.ts"
9
+ def initialize(args, *options)
10
+ @application_name = Rails.application.class.module_parent.to_s.underscore
11
+ super(args, *options)
12
+ end
13
+
14
+ def create_package_json
15
+ package_json_path = "package.json"
16
+
17
+ copy_file(package_json_path)
18
+ gsub_file(package_json_path, "\${application_name}", @application_name)
19
+ end
20
+
21
+ def create_sk_config
22
+ sk_config_path = "config/sewing-kit.config.ts"
11
23
 
12
- if File.exist?(config_path)
13
- say "Sewing kit config already exists"
14
- else
15
- copy_file "sewing-kit.config.ts", config_path
24
+ copy_file("sewing-kit.config.ts", sk_config_path)
25
+ gsub_file(sk_config_path, "\${application_name}", @application_name)
26
+ end
16
27
 
17
- say "Sewing kit config"
18
- end
28
+ def create_config_files
29
+ copy_file(".editorconfig")
30
+ copy_file(".eslintignore")
31
+ copy_file(".prettierignore")
19
32
  end
20
33
  end
21
34
  end
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "${application_name}",
3
+ "private": true,
4
+ "sideEffects": false,
5
+ "scripts": {
6
+ "dev": "sewing-kit dev",
7
+ "check": "sewing-kit check",
8
+ "lint": "sewing-kit lint",
9
+ "type-check": "sewing-kit type-check",
10
+ "nuke": "sewing-kit nuke",
11
+ "test": "sewing-kit test"
12
+ },
13
+ "eslintConfig": {
14
+ "extends": [
15
+ "plugin:@shopify/typescript",
16
+ "plugin:@shopify/react",
17
+ "plugin:@shopify/prettier",
18
+ "plugin:@shopify/jest",
19
+ "plugin:@shopify/polaris"
20
+ ]
21
+ },
22
+ "prettier": "@shopify/prettier-config",
23
+ "stylelint": {
24
+ "extends": [
25
+ "@shopify/stylelint-plugin/prettier"
26
+ ]
27
+ },
28
+ "resolutions": {
29
+ "babel-plugin-dynamic-import-node": "2.3.0"
30
+ }
31
+ }
@@ -1,7 +1,11 @@
1
1
  /* eslint-env node */
2
2
 
3
- import {Env, Plugins} from '@shopify/sewing-kit';
3
+ import {Plugins} from '@shopify/sewing-kit';
4
4
 
5
- export default function sewingKitConfig(_plugins: Plugins, _env: Env) {
6
- return {};
5
+ export default function sewingKitConfig(plugins: Plugins) {
6
+ return {
7
+ name: "${application_name}",
8
+ plugins: [
9
+ ],
10
+ };
7
11
  }
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Quilt
3
- VERSION = "1.12.2"
3
+ VERSION = "1.13.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quilt_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.2
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mathew Allen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-19 00:00:00.000000000 Z
11
+ date: 2020-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -95,11 +95,22 @@ files:
95
95
  - config/routes.rb
96
96
  - lib/generators/quilt/USAGE
97
97
  - lib/generators/quilt/install_generator.rb
98
- - lib/generators/quilt/templates/App.tsx
99
- - lib/generators/quilt/templates/routes.rb
100
- - lib/generators/quilt/templates/tsconfig.json
98
+ - lib/generators/quilt/rails_setup/USAGE
99
+ - lib/generators/quilt/rails_setup/rails_setup_generator.rb
100
+ - lib/generators/quilt/rails_setup/templates/Procfile
101
+ - lib/generators/quilt/rails_setup/templates/routes.rb
102
+ - lib/generators/quilt/react_app/USAGE
103
+ - lib/generators/quilt/react_app/react_app_generator.rb
104
+ - lib/generators/quilt/react_app/templates/App.tsx
105
+ - lib/generators/quilt/react_setup/USAGE
106
+ - lib/generators/quilt/react_setup/react_setup_generator.rb
107
+ - lib/generators/quilt/react_setup/templates/App.tsx
108
+ - lib/generators/quilt/react_setup/templates/tsconfig.json
109
+ - lib/generators/quilt_rails/USAGE
110
+ - lib/generators/quilt_rails/install_generator.rb
101
111
  - lib/generators/sewing_kit/USAGE
102
112
  - lib/generators/sewing_kit/install_generator.rb
113
+ - lib/generators/sewing_kit/templates/package.json
103
114
  - lib/generators/sewing_kit/templates/sewing-kit.config.ts
104
115
  - lib/quilt_rails.rb
105
116
  - lib/quilt_rails/configuration.rb