js-routes 2.1.0 → 2.2.1

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: 242f329ab92abe8be4a2fa3790f72a3f161a6c2355b2392eae484a36a91d3a24
4
- data.tar.gz: 120e5191eccfe3a8978c89ecb690a4f93a62279b249c58bc84b9273fe3e900c7
3
+ metadata.gz: 54158654106dece477c1fdf36afa52b504a43b8210c4c8d30f98d41ccd0ef600
4
+ data.tar.gz: a67b36754269392839bb6d2e86a20899ec2575437ac9667f10cdd9feb7306185
5
5
  SHA512:
6
- metadata.gz: e1998fd3c98dff227905bfcd8a09be8bb6901d3da7293b60d1a6f11c3a2627c623372324a13010cbe425eb7b93781fa64db042c08e7b4123d4a50ec8bd8814b2
7
- data.tar.gz: 5395c808f148bd39a99de0ce748cbb3a57c27620f048764bfcf6a455ac6ce2bbc43e282f4c660ba019f8d4b5df39a316728bb673d56b2667aecb667dde82d91b
6
+ metadata.gz: 582b6a39a062f6fcfd7b2cb4a57b4fd4573e343f93d5751ef764b7e3617cb7243801caf61ee971224a2c1a41e43a2f51221e5d3a40c12d5db21af98f47467044
7
+ data.tar.gz: f54b26ed68ed8ef2a6b4ad5ebf2e0322bfbec7385756a8578b5c11c01eca646d42baa5634d16cef6d16520e3eed4d1b1a37260e4ade943ee568b6b4755153cea
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  ## master
2
2
 
3
+ ## v2.2.1
4
+
5
+ * Improve generator to update route files on `assets:precompile` and add them to `.gitignore by default` [#288](https://github.com/railsware/js-routes/issues/288#issuecomment-1012182815)
6
+
7
+ ## v2.2.0
8
+
9
+ * Use Rack Middleware to automatically update routes file in development [#288](https://github.com/railsware/js-routes/issues/288)
10
+ * This setup is now a default recommended due to lack of any downside comparing to [ERB Loader](./Readme.md#webpacker) and [Manual Setup](./Readme.md#advanced-setup)
11
+
12
+ ## v2.1.3
13
+
14
+ * Fix `default_url_options` bug. [#290](https://github.com/railsware/js-routes/issues/290)
15
+
16
+ ## v2.1.2
17
+
18
+ * Improve browser window object detection. [#287](https://github.com/railsware/js-routes/issues/287)
19
+
20
+ ## v2.1.1
21
+
22
+ * Added webpacker generator `./bin/rails generate js_routes:webpacker`
23
+ * Reorganized Readme to describe different setups with their pros and cons more clearly
24
+
3
25
  ## v2.1.0
4
26
 
5
27
  * Support typescript defintions file aka `routes.d.ts`. See [Readme.md](./Readme.md#definitions) for more information.
data/Readme.md CHANGED
@@ -16,40 +16,84 @@ gem "js-routes"
16
16
 
17
17
  ## Setup
18
18
 
19
+ There are several possible ways to setup JsRoutes:
20
+
21
+ * [Quick and easy](#quick-start)
22
+ * Uses Rack Middleware to automatically update routes locally
23
+ * Works great for a simple Rails application
24
+ * [Webpacker ERB Loader](#webpacker)
25
+ * Requires ESM module system (the default)
26
+ * Doesn't support typescript definitions
27
+ * [Advanced Setup](#advanced-setup)
28
+ * Allows very custom setups
29
+ * [Sprockets](#sprockets) legacy
30
+ * Deprecated and not recommended for modern apps
31
+
32
+ <div id='quick-start'></div>
33
+
19
34
  ### Quick Start
20
35
 
21
- Run:
36
+ Setup [Rack Middleware](https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack)
37
+ to automatically generate and maintain `routes.js` file and corresponding
38
+ [Typescript definitions](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html) `routes.d.ts`:
39
+
40
+ #### Use a Generator
41
+
42
+ Run a command:
22
43
 
23
44
  ``` sh
24
- rake js:routes
25
- # OR for typescript support
26
- rake js:routes:typescript
45
+ rails generate js_routes:middleware
27
46
  ```
28
47
 
48
+ #### Setup Manually
29
49
 
30
- Individual routes can be imported using:
50
+ Add the following to `config/environments/development.rb`:
31
51
 
32
- ``` javascript
33
- import {edit_post_path, posts_path} from 'routes';
34
- console.log(posts_path({format: 'json'})) // => "/posts.json"
35
- console.log(edit_post_path(1)) // => "/posts/1/edit"
52
+ ``` ruby
53
+ config.middleware.use(JsRoutes::Middleware)
36
54
  ```
37
55
 
38
- Make routes available globally in `app/javascript/packs/application.js`:
56
+ Use it in `app/javascript/packs/application.js`:
39
57
 
40
58
  ``` javascript
41
- import * as Routes from 'routes';
42
- window.Routes = Routes;
59
+ import * as Routes from '../routes';
60
+ // window.Routes = Routes;
61
+ alert(Routes.post_path(1))
43
62
  ```
44
63
 
45
- **Note**: that this setup requires `rake js:routes` to be run each time routes file is updated.
64
+ Upgrade `rake assets:precompile` to update js-routes files:
65
+
66
+ ``` ruby
67
+ namespace :assets do
68
+ task :precompile => "js:routes:typescript"
69
+ end
70
+ ```
71
+
72
+ Add js-routes files to `.gitignore`:
73
+
74
+ ```
75
+ /app/javascript/routes.js
76
+ /app/javascript/routes.d.ts
77
+ ```
46
78
 
47
79
  <div id='webpacker'></div>
48
80
 
49
- #### Webpacker + automatic updates
81
+ ### Webpacker ERB loader
82
+
83
+ **IMPORTANT**: this setup doesn't support IDE autocompletion with [Typescript](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html)
84
+
50
85
 
86
+ #### Use a Generator
51
87
 
52
- This setup can automatically update your routes without `rake js:routes` being called manually.
88
+ Run a command:
89
+
90
+ ``` sh
91
+ ./bin/rails generate js_routes:webpacker
92
+ ```
93
+
94
+ #### Setup manually
95
+
96
+ The routes files can be automatically updated without `rake` task being called manually.
53
97
  It requires [rails-erb-loader](https://github.com/usabilityhub/rails-erb-loader) npm package to work.
54
98
 
55
99
  Add `erb` loader to webpacker:
@@ -63,16 +107,16 @@ Create webpack ERB config `config/webpack/loaders/erb.js`:
63
107
 
64
108
  ``` javascript
65
109
  module.exports = {
66
- test: /\.js\.erb$/,
67
- enforce: 'pre',
68
- exclude: /node_modules/,
69
- use: [{
70
- loader: 'rails-erb-loader',
71
- options: {
72
- runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
73
- }
74
- }]
75
- }
110
+ module: {
111
+ rules: [
112
+ {
113
+ test: /\.erb$/,
114
+ enforce: 'pre',
115
+ loader: 'rails-erb-loader'
116
+ },
117
+ ]
118
+ }
119
+ };
76
120
  ```
77
121
 
78
122
  Enable `erb` extension in `config/webpack/environment.js`:
@@ -95,23 +139,77 @@ import * as Routes from 'routes.js.erb';
95
139
  window.Routes = Routes;
96
140
  ```
97
141
 
142
+ <div id='advanced-setup'></div>
143
+
144
+ ### Advanced Setup
145
+
146
+ **IMPORTANT**: that this setup requires the JS routes file to be updates manually
147
+
148
+ Routes file can be generated with a `rake` task:
149
+
150
+ ``` sh
151
+ rake js:routes
152
+ # OR for typescript support
153
+ rake js:routes:typescript
154
+ ```
155
+
156
+ In case you need multiple route files for different parts of your application, you have to create the files manually.
157
+ If your application has an `admin` and an `application` namespace for example:
158
+
159
+ **IMPORTANT**: Requires [Webpacker ERB Loader](#webpacker) setup.
160
+
161
+ ``` erb
162
+ // app/javascript/admin/routes.js.erb
163
+ <%= JsRoutes.generate(include: /admin/) %>
164
+ ```
165
+
166
+ ``` erb
167
+ // app/javascript/customer/routes.js.erb
168
+ <%= JsRoutes.generate(exclude: /admin/) %>
169
+ ```
170
+
171
+ You can manipulate the generated helper manually by injecting ruby into javascript:
172
+
173
+ ``` erb
174
+ export const routes = <%= JsRoutes.generate(module_type: nil, namespace: nil) %>
175
+ ```
176
+
177
+ If you want to generate the routes files outside of the asset pipeline, you can use `JsRoutes.generate!`:
178
+
179
+ ``` ruby
180
+ path = Rails.root.join("app/javascript")
181
+
182
+ JsRoutes.generate!("#{path}/app_routes.js", exclude: [/^admin_/, /^api_/])
183
+ JsRoutes.generate!("#{path}/adm_routes.js", include: /^admin_/)
184
+ JsRoutes.generate!("#{path}/api_routes.js", include: /^api_/, default_url_options: {format: "json"})
185
+ ```
186
+
98
187
  <div id='definitions'></div>
99
188
 
100
189
  #### Typescript Definitions
101
190
 
102
- JsRoutes has typescript support out of the box. In order to generate typscript definitions file (aka `routes.d.ts`) you can call:
191
+ JsRoutes has typescript support out of the box.
192
+
193
+ Restrictions:
194
+
195
+ * Only available if `module_type` is set to `ESM` (strongly recommended and default).
196
+ * Webpacker Automatic Updates are not available because typescript compiler can not be configured to understand `.erb` extensions.
197
+
198
+ For the basic setup of typscript definitions see [Quick Start](#quick-start) setup.
199
+ More advanced setup would involve calling manually:
103
200
 
104
201
  ``` ruby
105
- JsRoutes.definitions!
202
+ JsRoutes.definitions! # to output to file
203
+ # or
204
+ JsRoutes.definitions # to output to string
106
205
  ```
107
206
 
108
- Or create an automatic updates file at `app/javascript/routes.d.ts.erb`:
207
+ Even more advanced setups can be achieved by setting `module_type` to `DTS` inside [configuration](#module_type)
208
+ which will cause any `JsRoutes` instance to generate defintions instead of routes themselves.
109
209
 
110
- ``` erb
111
- <%= JsRoutes.defintions %>
112
- ```
210
+ <div id="sprockets"></div>
113
211
 
114
- #### Sprockets (Deprecated)
212
+ ### Sprockets (Deprecated)
115
213
 
116
214
  If you are using [Sprockets](https://github.com/rails/sprockets-rails) you may configure js-routes in the following way.
117
215
 
@@ -140,7 +238,7 @@ This cache is not flushed on server restart in development environment.
140
238
 
141
239
  **Important:** If routes.js file is not updated after some configuration change you need to run this rake task again.
142
240
 
143
- ### Configuration
241
+ ## Configuration
144
242
 
145
243
  You can configure JsRoutes in two main ways. Either with an initializer (e.g. `config/initializers/js_routes.rb`):
146
244
 
@@ -150,7 +248,7 @@ JsRoutes.setup do |config|
150
248
  end
151
249
  ```
152
250
 
153
- Or dynamically in JavaScript, although only [Formatter Options](#formatter-options) are supported (see below)
251
+ Or dynamically in JavaScript, although only [Formatter Options](#formatter-options) are supported:
154
252
 
155
253
  ``` js
156
254
  import * as Routes from 'routes'
@@ -160,12 +258,14 @@ Routes.configure({
160
258
  Routes.config(); // current config
161
259
  ```
162
260
 
163
- #### Available Options
261
+ ### Available Options
164
262
 
165
- ##### Generator Options
263
+ #### Generator Options
166
264
 
167
265
  Options to configure JavaScript file generator. These options are only available in Ruby context but not JavaScript.
168
266
 
267
+ <div id='module-type'></div>
268
+
169
269
  * `module_type` - JavaScript module type for generated code. [Article](https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm)
170
270
  * Options: `ESM`, `UMD`, `CJS`, `AMD`, `DTS`, `nil`.
171
271
  * Default: `ESM`
@@ -196,7 +296,9 @@ Options to configure JavaScript file generator. These options are only available
196
296
  * `file` - a file location where generated routes are stored
197
297
  * Default: `app/javascript/routes.js` if setup with Webpacker, otherwise `app/assets/javascripts/routes.js` if setup with Sprockets.
198
298
 
199
- ##### Formatter Options
299
+ <div id="formatter-options"></div>
300
+
301
+ #### Formatter Options
200
302
 
201
303
  Options to configure routes formatting. These options are available both in Ruby and JavaScript context.
202
304
 
@@ -214,36 +316,6 @@ Options to configure routes formatting. These options are available both in Ruby
214
316
  * This option exists because JS doesn't provide a difference between an object and a hash
215
317
  * Default: `_options`
216
318
 
217
- ### Advanced Setup
218
-
219
- In case you need multiple route files for different parts of your application, you have to create the files manually.
220
- If your application has an `admin` and an `application` namespace for example:
221
-
222
- ``` erb
223
- // app/javascript/admin/routes.js.erb
224
- <%= JsRoutes.generate(include: /admin/) %>
225
- ```
226
-
227
- ``` erb
228
- // app/javascript/customer/routes.js.erb
229
- <%= JsRoutes.generate(exclude: /admin/) %>
230
- ```
231
-
232
- You can manipulate the generated helper manually by injecting ruby into javascript:
233
-
234
- ``` erb
235
- export const routes = <%= JsRoutes.generate(module_type: nil, namespace: nil) %>
236
- ```
237
-
238
- If you want to generate the routes files outside of the asset pipeline, you can use `JsRoutes.generate!`:
239
-
240
- ``` ruby
241
- path = Rails.root.join("app/javascript")
242
-
243
- JsRoutes.generate!("#{path}/app_routes.js", exclude: [/^admin_/, /^api_/])
244
- JsRoutes.generate!("#{path}/adm_routes.js", include: /^admin_/)
245
- JsRoutes.generate!("#{path}/api_routes.js", include: /^api_/, default_url_options: {format: "json"})
246
- ```
247
319
 
248
320
  ## Usage
249
321
 
@@ -252,22 +324,34 @@ Configuration above will create a nice javascript file with `Routes` object that
252
324
  ``` js
253
325
  import * as Routes from 'routes';
254
326
 
255
- Routes.users_path() // => "/users"
256
- Routes.user_path(1) // => "/users/1"
257
- Routes.user_path(1, {format: 'json'}) // => "/users/1.json"
258
- Routes.user_path(1, {anchor: 'profile'}) // => "/users/1#profile"
259
- Routes.new_user_project_path(1, {format: 'json'}) // => "/users/1/projects/new.json"
260
- Routes.user_project_path(1,2, {q: 'hello', custom: true}) // => "/users/1/projects/2?q=hello&custom=true"
261
- Routes.user_project_path(1,2, {hello: ['world', 'mars']}) // => "/users/1/projects/2?hello%5B%5D=world&hello%5B%5D=mars"
262
- ```
327
+ Routes.users_path()
328
+ // => "/users"
263
329
 
264
- Using serialized object as route function arguments:
330
+ Routes.user_path(1)
331
+ // => "/users/1"
332
+
333
+ Routes.user_path(1, {format: 'json'})
334
+ // => "/users/1.json"
335
+
336
+ Routes.user_path(1, {anchor: 'profile'})
337
+ // => "/users/1#profile"
338
+
339
+ Routes.new_user_project_path(1, {format: 'json'})
340
+ // => "/users/1/projects/new.json"
341
+
342
+ Routes.user_project_path(1,2, {q: 'hello', custom: true})
343
+ // => "/users/1/projects/2?q=hello&custom=true"
344
+
345
+ Routes.user_project_path(1,2, {hello: ['world', 'mars']})
346
+ // => "/users/1/projects/2?hello%5B%5D=world&hello%5B%5D=mars"
265
347
 
266
- ``` js
267
348
  var google = {id: 1, name: "Google"};
268
- Routes.company_path(google) // => "/companies/1"
349
+ Routes.company_path(google)
350
+ // => "/companies/1"
351
+
269
352
  var google = {id: 1, name: "Google", to_param: "google"};
270
- Routes.company_path(google) // => "/companies/google"
353
+ Routes.company_path(google)
354
+ // => "/companies/google"
271
355
  ```
272
356
 
273
357
  In order to make routes helpers available globally:
@@ -276,7 +360,7 @@ In order to make routes helpers available globally:
276
360
  jQuery.extend(window, Routes)
277
361
  ```
278
362
 
279
- ## Get spec of routes and required params
363
+ ### Get spec of routes and required params
280
364
 
281
365
  Possible to get `spec` of route by function `toString`:
282
366
 
@@ -361,14 +445,6 @@ Advantages of this one are:
361
445
  * Support Rails `#to_param` convention for seo optimized paths
362
446
  * Well tested
363
447
 
364
- ## Version 2 TODO
365
-
366
- * Add routes generation .d.ts file
367
- * Add config option on the output format: js, ts, d.ts
368
- * Add prettier
369
- * Add eslint
370
- * Add development guide
371
-
372
448
  #### Thanks to [contributors](https://github.com/railsware/js-routes/contributors)
373
449
 
374
450
  #### Have fun
@@ -0,0 +1,58 @@
1
+ require "rails/generators"
2
+
3
+ class JsRoutes::Generators::Middleware < Rails::Generators::Base
4
+
5
+ source_root File.expand_path(__FILE__ + "/../../../templates")
6
+
7
+ def create_middleware
8
+ copy_file "initializer.rb", "config/initializers/js_routes.rb"
9
+ inject_into_file "app/javascript/packs/application.js", pack_content
10
+ inject_into_file "config/environments/development.rb", middleware_content, before: /^end\n\z/
11
+ inject_into_file "Rakefile", rakefile_content
12
+ inject_into_file ".gitignore", gitignore_content
13
+ JsRoutes.generate!
14
+ JsRoutes.definitions!
15
+ end
16
+
17
+ protected
18
+
19
+ def pack_content
20
+ <<-JS
21
+ import * as Routes from '../routes';
22
+ window.Routes = Routes;
23
+ JS
24
+ end
25
+
26
+ def middleware_content
27
+ <<-RB
28
+
29
+ # Automatically update js-routes file
30
+ # when routes.rb is changed
31
+ config.middleware.use(JsRoutes::Middleware)
32
+ RB
33
+ end
34
+
35
+ def rakefile_content
36
+ <<-RB
37
+
38
+ # Update js-routes file before assets precompile
39
+ namespace :assets do
40
+ task :precompile => "js:routes:typescript"
41
+ end
42
+ RB
43
+ end
44
+
45
+ def gitignore_content
46
+ banner = <<-TXT
47
+
48
+ # Ignore automatically generated js-routes files.
49
+ TXT
50
+
51
+ banner + [
52
+ {},
53
+ {module_type: 'DTS'}
54
+ ].map do |config|
55
+ File.join('/', JsRoutes.new(config).configuration.output_file) + "\n"
56
+ end.join
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ require "rails/generators"
2
+
3
+ class JsRoutes::Generators::Webpacker < Rails::Generators::Base
4
+
5
+ source_root File.expand_path(__FILE__ + "/../../../templates")
6
+
7
+ def create_webpack
8
+ copy_file "initializer.rb", "config/initializers/js_routes.rb"
9
+ copy_file "erb.js", "config/webpack/loaders/erb.js"
10
+ copy_file "routes.js.erb", "app/javascript/routes.js.erb"
11
+ inject_into_file "config/webpack/environment.js", loader_content
12
+ inject_into_file "app/javascript/packs/application.js", pack_content
13
+ command = Rails.root.join("./bin/yarn add rails-erb-loader")
14
+ run command
15
+ end
16
+
17
+ protected
18
+
19
+ def pack_content
20
+ <<-JS
21
+ import * as Routes from 'routes.js.erb';
22
+ window.Routes = Routes;
23
+ JS
24
+ end
25
+
26
+ def loader_content
27
+ <<-JS
28
+ const erb = require('./loaders/erb')
29
+ environment.loaders.append('erb', erb)
30
+ JS
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ class JsRoutes
2
+ # A Rack middleware that automatically updates routes file
3
+ # whenever routes.rb is modified
4
+ #
5
+ # Inspired by
6
+ # https://github.com/fnando/i18n-js/blob/main/lib/i18n/js/middleware.rb
7
+ class Middleware
8
+ def initialize(app)
9
+ @app = app
10
+ @routes_file = Rails.root.join("config/routes.rb")
11
+ @mtime = nil
12
+ end
13
+
14
+ def call(env)
15
+ update_js_routes
16
+ @app.call(env)
17
+ end
18
+
19
+ protected
20
+
21
+ def update_js_routes
22
+ new_mtime = routes_mtime
23
+ unless new_mtime == @mtime
24
+ JsRoutes.generate!
25
+ JsRoutes.definitions!
26
+ @mtime = new_mtime
27
+ end
28
+ end
29
+
30
+ def routes_mtime
31
+ File.mtime(@routes_file)
32
+ rescue Errno::ENOENT
33
+ nil
34
+ end
35
+ end
36
+ end