staticky 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/README.md +378 -18
- data/lib/staticky/application.rb +36 -0
- data/lib/staticky/builder.rb +4 -2
- data/lib/staticky/cli/commands/build.rb +13 -0
- data/lib/staticky/cli/commands/generate.rb +67 -0
- data/lib/staticky/cli/commands/version.rb +13 -0
- data/lib/staticky/cli/commands.rb +13 -0
- data/lib/staticky/cli.rb +0 -60
- data/lib/staticky/deps.rb +1 -1
- data/lib/staticky/filesystem.rb +0 -3
- data/lib/staticky/phlex/view_helpers.rb +12 -2
- data/lib/staticky/pluggable.rb +35 -0
- data/lib/staticky/resource.rb +14 -15
- data/lib/staticky/resources/plugins/phlex.rb +42 -0
- data/lib/staticky/resources/plugins/prelude.rb +76 -0
- data/lib/staticky/resources/plugins.rb +9 -0
- data/lib/staticky/router.rb +13 -18
- data/lib/staticky/routing/plugins/prelude.rb +97 -0
- data/lib/staticky/routing/plugins.rb +9 -0
- data/lib/staticky/server.rb +5 -16
- data/lib/staticky/server_plugin.rb +37 -0
- data/lib/staticky/server_plugins/live_reloading.rb +58 -0
- data/lib/staticky/utils.rb +63 -0
- data/lib/staticky/version.rb +1 -1
- data/lib/staticky.rb +23 -11
- data/site_template/.gitignore +14 -0
- data/site_template/.ruby-version +1 -1
- data/site_template/Gemfile +5 -5
- data/site_template/Procfile.dev +2 -2
- data/site_template/README.md +27 -7
- data/site_template/Rakefile +33 -2
- data/site_template/{lib/component.rb → app/views/application_component.rb} +1 -1
- data/site_template/app/views/application_layout.rb +4 -0
- data/site_template/app/views/application_page.rb +5 -0
- data/site_template/app/views/errors/not_found.rb +1 -1
- data/site_template/app/views/errors/service_error.rb +1 -1
- data/site_template/app/views/layouts/error.rb +4 -6
- data/site_template/app/views/layouts/head.rb +5 -3
- data/site_template/app/views/layouts/site.rb +10 -23
- data/site_template/app/views/pages/home.rb +1 -1
- data/site_template/app/views/ui/footer.rb +1 -1
- data/site_template/app/views/ui/navbar.rb +1 -1
- data/site_template/bin/{lint → setup} +8 -2
- data/site_template/config/boot.rb +1 -2
- data/site_template/config/puma.rb +11 -0
- data/site_template/config/staticky.rb +3 -0
- data/site_template/config/vite.json +3 -1
- data/site_template/frontend/entrypoints/application.js +0 -1
- data/site_template/frontend/tailwindcss/variable_font_plugin.js +1 -1
- data/site_template/lib/icon.rb +2 -2
- data/site_template/nginx.conf +8 -1
- data/site_template/package.json +10 -15
- data/site_template/tailwind.config.js +12 -8
- data/site_template/vite.config.ts +0 -5
- metadata +50 -11
- data/lib/staticky/container.rb +0 -26
- data/lib/staticky/router/definition.rb +0 -49
- data/lib/staticky/view_context.rb +0 -17
- data/site_template/frontend/turbo_transitions.js +0 -54
- data/site_template/lib/layout.rb +0 -4
- data/site_template/lib/page.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65d9999164be324b93ee59cb6602a46b0c703e6e5f543801d4173164644e3ae9
|
4
|
+
data.tar.gz: '0834f3f08d1d8cf469b846cec8349e5427c0809a419cbeaf845bf8ed66e07535'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d762bb547a713f7c86e4de541c1ee81615b8d0b5ec6d70633b50a1ad77986addf27ae64b3fc133c7b9749267774093ff9c9b1c6be54c8294004503b7992b6e9b
|
7
|
+
data.tar.gz: 1103439135f08b7558e51eaf8a147febf2924f333f7f8b4b4c84ceeed24173d84c8ddc40d8aa4e25dd4fa4877a30a4b40bf37e3c14d23f78bac3391f1da324c2
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.0] - 2024-12-09
|
4
|
+
|
5
|
+
- Adds live reloading of pages during development using server side events
|
6
|
+
- Integrates live reloading with vite in site template
|
7
|
+
|
8
|
+
## [0.2.0] - 2024-09-24
|
9
|
+
|
10
|
+
- Adds plugin system akin to Roda and Sequel for `Resource` and `Router`
|
11
|
+
- Improves initial setup
|
12
|
+
- Adds better documentation
|
13
|
+
- Switches from `rerun` to `filewatcher` for triggering rebuilds
|
14
|
+
- Switches from `rackup` to `puma` for development server
|
15
|
+
- Updates default package manager to yarn stable
|
16
|
+
|
3
17
|
## [0.1.1] - 2024-08-18
|
4
18
|
|
5
19
|
- Fixes nginx and Dockerfile configs for default dokku deployments
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ first-class support for Phlex components.
|
|
8
8
|
I wanted to extend the developer experience of something like Rails but focused
|
9
9
|
on static sites.
|
10
10
|
|
11
|
-
I am using this
|
11
|
+
I am currently using this to create https://taintedcoders.com
|
12
12
|
|
13
13
|
- Hot reloading in development with Roda serving static files
|
14
14
|
- Docker deployment with NGINX
|
@@ -36,14 +36,151 @@ staticky new my_blog --url "https://example.com"
|
|
36
36
|
This will generate a new site at `./my_blog`, install your dependencies and run
|
37
37
|
`rspec` just to make sure everything got set up correctly.
|
38
38
|
|
39
|
+
You can append `--help` to any commands to see info:
|
40
|
+
|
41
|
+
```
|
42
|
+
staticky new --help
|
43
|
+
```
|
44
|
+
|
45
|
+
Which outputs:
|
46
|
+
|
47
|
+
```
|
48
|
+
Command:
|
49
|
+
staticky new
|
50
|
+
|
51
|
+
Usage:
|
52
|
+
staticky new PATH
|
53
|
+
|
54
|
+
Description:
|
55
|
+
Create new site
|
56
|
+
|
57
|
+
Arguments:
|
58
|
+
PATH # REQUIRED Relative path where the site will be generated
|
59
|
+
|
60
|
+
Options:
|
61
|
+
--url=VALUE, -u VALUE # Site URL, default: "https://example.com"
|
62
|
+
--title=VALUE, -t VALUE # Site title, default: "Example"
|
63
|
+
--description=VALUE, -d VALUE # Site description, default: "Example site"
|
64
|
+
--twitter=VALUE, -x VALUE # Twitter handle, default: ""
|
65
|
+
--help, -h # Print this help
|
66
|
+
```
|
67
|
+
|
68
|
+
### Plugins
|
69
|
+
|
70
|
+
The router and resources use the plugin
|
71
|
+
[pattern](https://janko.io/the-plugin-system-of-sequel-and-roda/)
|
72
|
+
found in [Sequel](https://github.com/jeremyevans/sequel) and
|
73
|
+
[Roda](https://github.com/jeremyevans/roda).
|
74
|
+
|
75
|
+
This means you can easily extend each of them with plugins to fit the specific
|
76
|
+
content of your site.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
module MyResourcePlugin
|
80
|
+
module InstanceMethods
|
81
|
+
def component=(component)
|
82
|
+
@component = component
|
83
|
+
end
|
84
|
+
|
85
|
+
def component
|
86
|
+
return @component if defined?(@component)
|
87
|
+
|
88
|
+
raise ArgumentError, "component is required"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
In our own classes we can now reference our new plugin:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
class SomeResource < Staticky::Resource
|
98
|
+
plugin MyResourcePlugin
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
Or, if we register the plugin with `register_plugin` we can just use our
|
103
|
+
shorter symbol:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
Staticky::Resources::Plugins.register_plugin(:something, MyResourcePlugin)
|
107
|
+
|
108
|
+
class SomeResource < Staticky::Resource
|
109
|
+
plugin :something
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
This system lets you define your own specific resources by subclassing and
|
114
|
+
extending with your own plugins.
|
115
|
+
|
116
|
+
Here is an example of hooking into the output of the component
|
117
|
+
(a string of HTML):
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
module MinifyHTML
|
121
|
+
module InstanceMethods
|
122
|
+
# Calling super works because the base class has no methods, everything is
|
123
|
+
# a plugin including the core behavior of a resource.
|
124
|
+
def build
|
125
|
+
SomehowMinifyTheHTML.call(super)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
Staticky::Resources::Plugins.register_plugin(:minify_html, MinifyHTML)
|
131
|
+
|
132
|
+
class ApplicationResource < Staticky::Resource
|
133
|
+
plugin :minify_html
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
Now when an `ApplicationResource` gets rendered, its final output (a string of
|
138
|
+
HTML) will be minified.
|
139
|
+
|
140
|
+
Each plugin can define modules for:
|
141
|
+
|
142
|
+
|Name|Description|
|
143
|
+
|----|-----------|
|
144
|
+
|InstanceMethods|Get added as instance methods of the Resource|
|
145
|
+
|ClassMethods|Get added as the class methods of the Resource|
|
146
|
+
|
147
|
+
In addition you have methods you can define that let you hook into the resource
|
148
|
+
that adds your plugins:
|
149
|
+
|
150
|
+
|Name|Description|
|
151
|
+
|----|-----------|
|
152
|
+
|load_dependencies(plugin, ...)|Hook to load any other plugins required by this one|
|
153
|
+
|configure(plugin, ...)|Hook for additional setup required on the class|
|
154
|
+
|
155
|
+
|
156
|
+
### Routing
|
157
|
+
|
158
|
+
Your router is a plugin system that by default only has one plugin:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
plugin :prelude
|
162
|
+
```
|
163
|
+
|
164
|
+
This gives you the `match` and `root` methods in your router. You can override
|
165
|
+
or extend these methods yourself by redefining them (and optionally calling
|
166
|
+
`super`) inside your own plugin or class that inherits from the router.
|
167
|
+
|
39
168
|
Once your site is generated you can use the router to define how your content
|
40
169
|
maps to routes in `config/routes.rb`:
|
41
170
|
|
42
171
|
```ruby
|
43
172
|
Staticky.router.define do
|
44
173
|
root to: Pages::Home
|
174
|
+
|
175
|
+
# We can pass in a phlex class
|
45
176
|
match "404", to: Errors::NotFound
|
46
|
-
|
177
|
+
# Or an instance
|
178
|
+
match "500", to: Errors::ServiceError.new
|
179
|
+
|
180
|
+
# We can specify the resource type
|
181
|
+
match "about",
|
182
|
+
to: Markdown.new("content/posts/about.md"),
|
183
|
+
as: Resources::Markdown
|
47
184
|
|
48
185
|
# Write your own logic to parse your data into components
|
49
186
|
Site.posts.each_value do |model|
|
@@ -56,13 +193,139 @@ Each route takes a Phlex component (or any object that outputs a string from
|
|
56
193
|
`#call`). We can either pass the class for a default initialization (we just
|
57
194
|
call `.new`) or initialize it ourselves.
|
58
195
|
|
196
|
+
The resource will be initialized with a `component` and a `url`. It is used as
|
197
|
+
the view context for your phlex components.
|
198
|
+
|
199
|
+
#### Match
|
200
|
+
|
201
|
+
This works in a similar way to your Rails routes. Match takes a path and
|
202
|
+
a component (either a class or an instance) that it will route to.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
match "404", to: Errors::NotFound, as: Resource
|
206
|
+
```
|
207
|
+
|
208
|
+
#### Root
|
209
|
+
|
210
|
+
Using `match` you can define a root path like:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
match "/", to: Pages::Home
|
214
|
+
```
|
215
|
+
|
216
|
+
For convenience you can shorten this using `root`:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
root to: Pages::Home
|
220
|
+
```
|
221
|
+
|
222
|
+
### Resources
|
223
|
+
|
224
|
+
They initialize the same way `ActiveModel` objects do. That is they take their
|
225
|
+
keywords and call the setter according to the keys:
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
def new(**env)
|
229
|
+
super().tap do |resource|
|
230
|
+
env.each do |key, value|
|
231
|
+
resource.send(:"#{key}=", value)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
The base resource has two core plugins it includes by default:
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
plugin :prelude
|
241
|
+
plugin :phlex
|
242
|
+
```
|
243
|
+
|
244
|
+
Routes define your resources, which in the end are just data objects that
|
245
|
+
contain all the information required to produce the static file that eventually
|
246
|
+
outputs to your `Staticky.build_path`.
|
247
|
+
|
248
|
+
Lets say we had a router defined like:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
Staticky.router.define do
|
252
|
+
match "foo", to: Component
|
253
|
+
match "bar", to: Component
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
Then we could view our resources:
|
258
|
+
|
259
|
+
```
|
260
|
+
(ruby) Staticky.resources
|
261
|
+
[#<Staticky::Resource:0x0000711525d82c18
|
262
|
+
@component=#<Component:0x0000711525d74848>,
|
263
|
+
@destination=#<Pathname:/your-site-folder/build>,
|
264
|
+
@uri=#<URI::Generic /foo>,
|
265
|
+
@url="foo">,
|
266
|
+
#<Staticky::Resource:0x0000711525d82a88
|
267
|
+
@component=#<Component:0x0000711525d74208>,
|
268
|
+
@destination=#<Pathname:/your-site-folder/build>,
|
269
|
+
@uri=#<URI::Generic /bar>,
|
270
|
+
@url="bar">]
|
271
|
+
```
|
272
|
+
|
273
|
+
The `prelude` plugin provides the following methods:
|
274
|
+
|
275
|
+
|Method|Description|
|
276
|
+
|------|-----------|
|
277
|
+
|`build_path`|`Pathname` of where the component's output will be written to|
|
278
|
+
|`read`|Read the output of the resource from the file system|
|
279
|
+
|`filepath`|The file path (e.g. `about/index.html`) for the resource|
|
280
|
+
|`root?`|Whether or not the resource is the root path|
|
281
|
+
|
282
|
+
While the `phlex` plugin provides:
|
283
|
+
|
284
|
+
|Method|Description|
|
285
|
+
|------|-----------|
|
286
|
+
|`build`|Call the component and output its result as a string|
|
287
|
+
|
288
|
+
These resources are used by your site builder to output the files that end up in
|
289
|
+
the `Staticky.build_path`.
|
290
|
+
|
291
|
+
Each resource needs to have a `#build` method that creates a file in your build
|
292
|
+
folder.
|
293
|
+
|
294
|
+
The `phlex` plugin will call your components with a `ViewContext` just like
|
295
|
+
`ActionView` in Rails. But this context is tailored towards your static site.
|
296
|
+
|
297
|
+
This view context is a `SimpleDelegator` to your resource with a few extra
|
298
|
+
methods:
|
299
|
+
|
300
|
+
|Method|Description|
|
301
|
+
|------|-----------|
|
302
|
+
|`root?`|Whether or not this resource is for the root page|
|
303
|
+
|`current_path`|The path of the current resource being rendered|
|
304
|
+
|
305
|
+
These are useful for creating pages that hide or show content depending on which
|
306
|
+
path of the site we are building.
|
307
|
+
|
308
|
+
### Linking to your routes
|
309
|
+
|
310
|
+
First you need to include the view helpers somewhere in your component
|
311
|
+
hierarchy:
|
312
|
+
|
313
|
+
```ruby
|
314
|
+
class Component < Phlex::HTML
|
315
|
+
include Staticky::Phlex::ViewHelpers
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
This will add `link_to` to all your components which uses the router to resolve
|
320
|
+
any URLs via their path.
|
321
|
+
|
59
322
|
Here is an example of what the `Posts::Show` component might look like. We are
|
60
323
|
using a [protos](https://github.com/inhouse-work/protos) component, but you can
|
61
324
|
use plain old Phlex components if you like.
|
62
325
|
|
63
326
|
```ruby
|
64
327
|
module Posts
|
65
|
-
class Show <
|
328
|
+
class Show < ApplicationComponent
|
66
329
|
param :post, reader: false
|
67
330
|
|
68
331
|
def around_template(&)
|
@@ -70,7 +333,12 @@ module Posts
|
|
70
333
|
end
|
71
334
|
|
72
335
|
def view_template
|
73
|
-
|
336
|
+
# Links can be resolved to component classes if they are unique:
|
337
|
+
link_to "Home", Pages::Home
|
338
|
+
# They can also resolve via their url:
|
339
|
+
link_to "Posts", "/posts"
|
340
|
+
# Absolute links are resolved as is:
|
341
|
+
link_to "Email", "mailto:email@example.com"
|
74
342
|
|
75
343
|
render Posts::Header.new(@post)
|
76
344
|
render Posts::Outline.new(@post, class: css[:outline])
|
@@ -82,28 +350,37 @@ module Posts
|
|
82
350
|
|
83
351
|
def theme
|
84
352
|
{
|
85
|
-
layout: "
|
86
|
-
outline:
|
87
|
-
|
88
|
-
md:fixed
|
89
|
-
md:left-0
|
90
|
-
md:top-[--navbar-height]
|
91
|
-
md:pl-[--viewport-padding]
|
92
|
-
md:w-[--sidebar-width]
|
93
|
-
],
|
94
|
-
post: "prose mx-auto pb-lg"
|
353
|
+
layout: "bg-background",
|
354
|
+
outline: "border",
|
355
|
+
post: "max-w-prose mx-auto"
|
95
356
|
}
|
96
357
|
end
|
97
358
|
end
|
98
359
|
end
|
99
360
|
```
|
100
361
|
|
101
|
-
|
102
|
-
|
362
|
+
The advantage of using `link_to` over plain old `a` tags is that changes to your
|
363
|
+
routes will raise errors on invalidated links instead of silently
|
364
|
+
linking to invalid pages.
|
365
|
+
|
366
|
+
If your component is unique then you can link directly to them (if its not
|
367
|
+
unique then it will link to the last defined `match`):
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
link_to("Some link", Pages::Home)
|
371
|
+
```
|
372
|
+
|
373
|
+
Otherwise you can link to the path itself:
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
link_to("Some link", "/")
|
377
|
+
```
|
378
|
+
|
379
|
+
### Building your site
|
103
380
|
|
104
381
|
When you are developing your site you run `bin/dev` to start your development
|
105
|
-
server on http://localhost:
|
106
|
-
period when you make changes.
|
382
|
+
server on [http://localhost:3000](http://localhost:3000).
|
383
|
+
This will automatically reload after a short period when you make changes.
|
107
384
|
|
108
385
|
Assets are handled by Vite by default, but you can have whatever build process
|
109
386
|
you like just by tweaking `Procfile.dev` and your `Rakefile`. You will also need
|
@@ -140,6 +417,18 @@ These are available in your Phlex components under `helpers` (if you are using
|
|
140
417
|
the site template). This matches what you might expect when using Phlex in
|
141
418
|
Rails with `phlex-rails`.
|
142
419
|
|
420
|
+
## Live reloading
|
421
|
+
|
422
|
+
The development server has been hooked up with some live reloading using
|
423
|
+
server-side events.
|
424
|
+
|
425
|
+
A javascript script is inserted into the `<head>` tag during development which
|
426
|
+
will poll the `_staticky/live_reloading` endpoint. If files have changed then
|
427
|
+
a reload is triggered with `Turbo` if available, and just plain
|
428
|
+
`window.location.reload()` if not.
|
429
|
+
|
430
|
+
You can toggle this off by setting `live_reloading` to false inside the config.
|
431
|
+
|
143
432
|
## Configuration
|
144
433
|
|
145
434
|
We can override the configuration according to the settings defined on the main
|
@@ -152,6 +441,77 @@ Staticky.configure do |config|
|
|
152
441
|
config.root_path = Pathname(__dir__)
|
153
442
|
config.logger = Logger.new($stdout)
|
154
443
|
config.server_logger = Logger.new($stdout)
|
444
|
+
config.live_reloading = false
|
445
|
+
end
|
446
|
+
```
|
447
|
+
|
448
|
+
### Environment
|
449
|
+
|
450
|
+
You can define the environment of Staticky through its config.
|
451
|
+
|
452
|
+
```ruby
|
453
|
+
Staticky.configure do |config|
|
454
|
+
config.env = :test
|
455
|
+
end
|
456
|
+
```
|
457
|
+
|
458
|
+
This lets you write environment specific code:
|
459
|
+
|
460
|
+
```ruby
|
461
|
+
if Staticky.env.test?
|
462
|
+
# Do something test specific
|
463
|
+
end
|
464
|
+
```
|
465
|
+
|
466
|
+
## Testing
|
467
|
+
|
468
|
+
We can setup a separate testing environment by putting the following
|
469
|
+
into your `spec/spec_helper.rb`:
|
470
|
+
|
471
|
+
```ruby
|
472
|
+
Staticky.configure do |config|
|
473
|
+
config.root_path = Pathname.new(__dir__).join("fixtures")
|
474
|
+
config.build_path = Pathname.new(__dir__).join("fixtures/build")
|
475
|
+
config.env = :test
|
476
|
+
end
|
477
|
+
```
|
478
|
+
|
479
|
+
This sets up our build path to something different than our development builds.
|
480
|
+
|
481
|
+
Staticky uses `Dry::System` to manage its dependencies which means you can stub
|
482
|
+
them out if you want:
|
483
|
+
|
484
|
+
```ruby
|
485
|
+
require "dry/system/stubs"
|
486
|
+
|
487
|
+
Staticky.application.enable_stubs!
|
488
|
+
|
489
|
+
RSpec.configure do |config|
|
490
|
+
config.before do
|
491
|
+
Staticky.application.stub(:files, Staticky::Filesystem.test)
|
492
|
+
end
|
493
|
+
end
|
494
|
+
```
|
495
|
+
|
496
|
+
This lets you test your builds using `dry-files` (actually `staticky-files`, but
|
497
|
+
the interface is the same with additional capabilities for file folders).
|
498
|
+
|
499
|
+
The advantage of this is that we can perform our builds on a temporary in memory
|
500
|
+
file system rather than actually writing to our disk.
|
501
|
+
|
502
|
+
The plugins themselves can also be stubbed:
|
503
|
+
|
504
|
+
```ruby
|
505
|
+
require "dry/system/stubs"
|
506
|
+
|
507
|
+
Staticky::Resources::Plugins.enable_stubs!
|
508
|
+
Staticky::Routing::Plugins.enable_stubs!
|
509
|
+
|
510
|
+
RSpec.configure do |config|
|
511
|
+
config.before do
|
512
|
+
Staticky::Resources::Plugins.stub(:prelude, MyOwnResourcePlugin)
|
513
|
+
Staticky::Routing::Plugins.stub(:prelude, MyOwnRoutingPlugin)
|
514
|
+
end
|
155
515
|
end
|
156
516
|
```
|
157
517
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Staticky
|
4
|
+
class Application < Dry::System::Container
|
5
|
+
# This class coordinates the booting process to add our dependencies.
|
6
|
+
# We use zeitwerk to autoload our constants in the lib/staticky folder.
|
7
|
+
#
|
8
|
+
# Monitoring is enabled to hook into calls to certain dependencies.
|
9
|
+
#
|
10
|
+
# ```ruby
|
11
|
+
# Staticky.application.monitor(:builder, methods: %i[call]) do |event|
|
12
|
+
# Staticky.logger.info "Built site in #{event[:time]}ms"
|
13
|
+
# end
|
14
|
+
# ```
|
15
|
+
|
16
|
+
use :zeitwerk
|
17
|
+
use :monitoring
|
18
|
+
|
19
|
+
configure do |config|
|
20
|
+
config.root = Pathname(__dir__).join("..").join("..")
|
21
|
+
config.inflector = Dry::Inflector.new do |inflections|
|
22
|
+
inflections.acronym("CLI")
|
23
|
+
end
|
24
|
+
config.component_dirs.add "lib" do |dir|
|
25
|
+
dir.add_to_load_path = false
|
26
|
+
dir.auto_register = false
|
27
|
+
dir.namespaces.add "staticky", key: nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register(:files, memoize: true) { Staticky::Filesystem.real }
|
32
|
+
register(:router, memoize: true) { Staticky::Router.new }
|
33
|
+
register(:builder, memoize: true) { Staticky::Builder.new }
|
34
|
+
register(:generator) { Staticky::Generator.new }
|
35
|
+
end
|
36
|
+
end
|
data/lib/staticky/builder.rb
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module Staticky
|
4
4
|
class Builder
|
5
|
-
|
5
|
+
# Publisher needs to have a different name vs the application monitor
|
6
|
+
# https://github.com/dry-rb/dry-events/issues/6
|
7
|
+
include Dry::Events::Publisher[:building]
|
6
8
|
include Deps[:files, :router]
|
7
9
|
|
8
10
|
register_event("started")
|
@@ -28,7 +30,7 @@ module Staticky
|
|
28
30
|
.resources
|
29
31
|
.each do |resource|
|
30
32
|
publish("before_resource", resource:)
|
31
|
-
compile
|
33
|
+
compile resource.build_path, resource.build
|
32
34
|
publish("after_resource", resource:)
|
33
35
|
end
|
34
36
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Staticky
|
4
|
+
module CLI
|
5
|
+
module Commands
|
6
|
+
class Generate < Dry::CLI::Command
|
7
|
+
desc "Create new site"
|
8
|
+
|
9
|
+
argument :path,
|
10
|
+
required: true,
|
11
|
+
desc: "Relative path where the site will be generated"
|
12
|
+
|
13
|
+
option :url,
|
14
|
+
default: "https://example.com",
|
15
|
+
desc: "Site URL",
|
16
|
+
aliases: ["-u"]
|
17
|
+
option :title,
|
18
|
+
default: "Example",
|
19
|
+
desc: "Site title",
|
20
|
+
aliases: ["-t"]
|
21
|
+
option :description,
|
22
|
+
default: "Example site",
|
23
|
+
desc: "Site description",
|
24
|
+
aliases: ["-d"]
|
25
|
+
option :twitter,
|
26
|
+
default: "",
|
27
|
+
desc: "Twitter handle",
|
28
|
+
aliases: ["-x"]
|
29
|
+
|
30
|
+
def call(path:, **)
|
31
|
+
path = Pathname.new(path).expand_path
|
32
|
+
|
33
|
+
Staticky.generator.call(path, **)
|
34
|
+
|
35
|
+
Dir.chdir(path) do
|
36
|
+
system("cd #{path}")
|
37
|
+
system("chmod +x bin/*")
|
38
|
+
bundle_command("install")
|
39
|
+
bundle_command("exec bin/setup")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def bundle_command(command, env = {})
|
44
|
+
puts "bundle #{command}"
|
45
|
+
|
46
|
+
# We are going to shell out rather than invoking Bundler::CLI.new(command)
|
47
|
+
# because `rails new` loads the Thor gem and on the other hand bundler uses
|
48
|
+
# its own vendored Thor, which could be a different version. Running both
|
49
|
+
# things in the same process is a recipe for a night with paracetamol.
|
50
|
+
#
|
51
|
+
# Thanks to James Tucker for the Gem tricks involved in this call.
|
52
|
+
_bundle_command = Gem.bin_path("bundler", "bundle")
|
53
|
+
|
54
|
+
require "bundler"
|
55
|
+
Bundler.with_original_env do
|
56
|
+
exec_bundle_command(_bundle_command, command, env)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def exec_bundle_command(bundle_command, command, env)
|
61
|
+
full_command = %("#{Gem.ruby}" "#{bundle_command}" #{command})
|
62
|
+
system(env, full_command)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|