jekyll-uj-powertools 1.6.24 → 1.7.1
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/README.md +116 -0
- data/jekyll-uj-powertools.gemspec +5 -1
- data/lib/generators/dynamic-pages.rb +152 -0
- data/lib/generators/inject-properties.rb +1 -1
- data/lib/generators/limit-collections.rb +56 -0
- data/lib/hooks/parallel-build.rb +129 -0
- data/lib/jekyll-uj-powertools.rb +4 -0
- metadata +34 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a39cadef84f1c25e0d674e7004e3f6f041f94d27d5df354eea0f31d1c86bc8e3
|
|
4
|
+
data.tar.gz: 12f5642a57b3c8bd4dd7a62f1392c95fa665871c2dc304fdd2f2f75432619d40
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2c52117d2069807c586ad07e37792fca82216786528d1ecea4d304941f559fa808bc2b8c4bb2eac20dc84c1a9135956fe1c1db35651386336a3ec6053e3ef5c
|
|
7
|
+
data.tar.gz: a62ca9ec4f212468d6c2e8ade617843907dd46c68f76b328d3e0351424c286554a974ec63add70f4f1931e0e38859c7fe83c7f26b4a1004fa56fbeda607601ea
|
data/README.md
CHANGED
|
@@ -294,6 +294,122 @@ Creates language-specific URLs for multilingual sites.
|
|
|
294
294
|
{% uj_translation_url target_lang, "/pricing" %}
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
+
## Generators
|
|
298
|
+
|
|
299
|
+
### Dynamic Pages Generator
|
|
300
|
+
Automatically generate pages from collection data based on frontmatter fields. This is useful for creating category, tag, or any taxonomy pages dynamically without manually creating each page.
|
|
301
|
+
|
|
302
|
+
#### Configuration
|
|
303
|
+
Add to your `_config.yml`:
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
generators:
|
|
307
|
+
collection_categories:
|
|
308
|
+
# Example 1: Extract category from nested frontmatter field
|
|
309
|
+
- collection: recipes
|
|
310
|
+
field: recipe.cuisine # Dot notation for nested fields
|
|
311
|
+
layout: recipe-category
|
|
312
|
+
permalink: /recipes/:slug
|
|
313
|
+
title: ":name Recipes"
|
|
314
|
+
description: "Browse our collection of :name recipes."
|
|
315
|
+
|
|
316
|
+
# Example 2: Simple frontmatter field
|
|
317
|
+
- collection: products
|
|
318
|
+
field: category
|
|
319
|
+
layout: product-category
|
|
320
|
+
permalink: /products/:slug
|
|
321
|
+
title: ":name Products"
|
|
322
|
+
description: "Shop our :name products."
|
|
323
|
+
|
|
324
|
+
# Example 3: Minimal config (uses defaults)
|
|
325
|
+
- collection: articles
|
|
326
|
+
field: category
|
|
327
|
+
layout: article-category
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### Template Variables
|
|
331
|
+
Use these placeholders in `title`, `description`, and `permalink`:
|
|
332
|
+
- `:name` - The formatted category name (e.g., "Asian Cuisine")
|
|
333
|
+
- `:slug` - The URL-safe slug (e.g., "asian-cuisine")
|
|
334
|
+
|
|
335
|
+
#### Defaults
|
|
336
|
+
- `permalink`: `/:collection/:slug` (e.g., `/recipes/asian`)
|
|
337
|
+
- `title`: `:name`
|
|
338
|
+
- `description`: `Browse our collection of :name.`
|
|
339
|
+
|
|
340
|
+
#### Generated Page Data
|
|
341
|
+
Each generated page includes the following data accessible in the layout:
|
|
342
|
+
- `page.title` - The formatted title
|
|
343
|
+
- `page.description` - The formatted description
|
|
344
|
+
- `page.category_slug` - URL-safe slug (e.g., "asian-cuisine")
|
|
345
|
+
- `page.category_name` - Human-readable name (e.g., "Asian Cuisine")
|
|
346
|
+
- `page.collection_name` - Source collection name (e.g., "recipes")
|
|
347
|
+
- `page.meta.title` - SEO title with site name appended
|
|
348
|
+
- `page.meta.description` - SEO description
|
|
349
|
+
|
|
350
|
+
#### Example Layout
|
|
351
|
+
Create a layout file (e.g., `_layouts/recipe-category.html`) to display the category page:
|
|
352
|
+
|
|
353
|
+
```liquid
|
|
354
|
+
---
|
|
355
|
+
layout: default
|
|
356
|
+
---
|
|
357
|
+
<h1>{{ page.category_name }}</h1>
|
|
358
|
+
<p>{{ page.description }}</p>
|
|
359
|
+
|
|
360
|
+
{% assign items = site.recipes | where_exp: "item", "item.recipe.cuisine == page.category_name" %}
|
|
361
|
+
{% for item in items %}
|
|
362
|
+
<article>
|
|
363
|
+
<h2><a href="{{ item.url }}">{{ item.title }}</a></h2>
|
|
364
|
+
</article>
|
|
365
|
+
{% endfor %}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Parallel Build
|
|
369
|
+
Speed up Jekyll builds by rendering pages and documents in parallel using multiple CPU threads. This can significantly reduce build times for sites with many pages.
|
|
370
|
+
|
|
371
|
+
**Enabled by default** - no configuration needed! The plugin automatically uses all available CPU cores.
|
|
372
|
+
|
|
373
|
+
### Configuration
|
|
374
|
+
Customize parallel build behavior in `_config.yml`:
|
|
375
|
+
|
|
376
|
+
```yaml
|
|
377
|
+
parallel_build:
|
|
378
|
+
enabled: true # Enable/disable parallel builds (default: true)
|
|
379
|
+
threads: 8 # Number of threads (default: number of CPU cores)
|
|
380
|
+
min_items: 1 # Minimum items before parallelizing (default: 1)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Disabling Parallel Build
|
|
384
|
+
If you encounter issues with thread-safety in custom Liquid tags:
|
|
385
|
+
|
|
386
|
+
```yaml
|
|
387
|
+
# Option 1: Disable entirely
|
|
388
|
+
parallel_build: false
|
|
389
|
+
|
|
390
|
+
# Option 2: Disable via enabled flag
|
|
391
|
+
parallel_build:
|
|
392
|
+
enabled: false
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Performance Tips
|
|
396
|
+
- Parallel builds work best with CPU-bound Liquid rendering
|
|
397
|
+
- For maximum speed, combine with `limit_collections` during development
|
|
398
|
+
- Use `--profile` to identify slow templates that benefit most from parallelization
|
|
399
|
+
|
|
400
|
+
## Development Config (`_config.dev.yml`)
|
|
401
|
+
Speed up dev builds by limiting collections. Create `_config.dev.yml` in your Jekyll source:
|
|
402
|
+
|
|
403
|
+
```yaml
|
|
404
|
+
limit_collections:
|
|
405
|
+
recipes: 50
|
|
406
|
+
products: 20
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Run with: `bundle exec jekyll serve --config _config.yml,_config.dev.yml`
|
|
410
|
+
|
|
411
|
+
UJ auto-loads this file in dev mode.
|
|
412
|
+
|
|
297
413
|
## Final notes
|
|
298
414
|
These examples show how you can use the features of `jekyll-uj-powertools` in your Jekyll site.
|
|
299
415
|
|
|
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
# Gem info
|
|
7
7
|
spec.name = "jekyll-uj-powertools"
|
|
8
|
-
spec.version = "1.
|
|
8
|
+
spec.version = "1.7.1"
|
|
9
9
|
|
|
10
10
|
# Author info
|
|
11
11
|
spec.authors = ["ITW Creative Works"]
|
|
@@ -31,10 +31,14 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
spec.add_development_dependency "rake"
|
|
32
32
|
spec.add_development_dependency "rspec"
|
|
33
33
|
spec.add_development_dependency "simplecov"
|
|
34
|
+
spec.add_development_dependency "ostruct"
|
|
34
35
|
|
|
35
36
|
# Translation and HTML manipulation requires Nokogiri
|
|
36
37
|
spec.add_runtime_dependency 'nokogiri', '>= 1.17'
|
|
37
38
|
|
|
39
|
+
# Parallel processing for faster builds
|
|
40
|
+
spec.add_runtime_dependency 'parallel', '>= 1.20'
|
|
41
|
+
|
|
38
42
|
# Ruby version
|
|
39
43
|
spec.required_ruby_version = ">= 2.0.0"
|
|
40
44
|
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Dynamic Pages Generator
|
|
2
|
+
# Automatically generates pages from collection data based on config
|
|
3
|
+
#
|
|
4
|
+
# Usage in _config.yml:
|
|
5
|
+
#
|
|
6
|
+
# generators:
|
|
7
|
+
# collection_categories:
|
|
8
|
+
# # Example 1: Extract category from frontmatter field
|
|
9
|
+
# - collection: recipes
|
|
10
|
+
# field: recipe.cuisine # Dot notation for nested fields
|
|
11
|
+
# layout: recipe-category
|
|
12
|
+
# permalink: /recipes/:slug
|
|
13
|
+
# title: ":name Recipes"
|
|
14
|
+
# description: "Browse our collection of :name recipes."
|
|
15
|
+
#
|
|
16
|
+
# # Example 2: Simple frontmatter field
|
|
17
|
+
# - collection: products
|
|
18
|
+
# field: category
|
|
19
|
+
# layout: product-category
|
|
20
|
+
# permalink: /products/:slug
|
|
21
|
+
# title: ":name Products"
|
|
22
|
+
# description: "Shop our :name products."
|
|
23
|
+
#
|
|
24
|
+
# # Example 3: Minimal config (uses defaults)
|
|
25
|
+
# - collection: articles
|
|
26
|
+
# field: category
|
|
27
|
+
# layout: article-category
|
|
28
|
+
#
|
|
29
|
+
# Template variables for title/description/permalink:
|
|
30
|
+
# :name - The formatted category name (e.g., "Asian Cuisine")
|
|
31
|
+
# :slug - The URL-safe slug (e.g., "asian-cuisine")
|
|
32
|
+
#
|
|
33
|
+
# Defaults:
|
|
34
|
+
# permalink: /:collection/:slug (e.g., /recipes/asian)
|
|
35
|
+
# title: :name
|
|
36
|
+
# description: "Browse our collection of :name."
|
|
37
|
+
|
|
38
|
+
module Jekyll
|
|
39
|
+
class DynamicPagesGenerator < Generator
|
|
40
|
+
safe true
|
|
41
|
+
priority :normal # Run before InjectProperties (:low) so dynamic pages get resolved data
|
|
42
|
+
|
|
43
|
+
def generate(site)
|
|
44
|
+
config = site.config.dig('generators', 'collection_categories')
|
|
45
|
+
return unless config.is_a?(Array)
|
|
46
|
+
|
|
47
|
+
config.each do |category_config|
|
|
48
|
+
generate_category_pages(site, category_config)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def generate_category_pages(site, config)
|
|
55
|
+
collection_name = config['collection']
|
|
56
|
+
field = config['field']
|
|
57
|
+
return unless collection_name && field
|
|
58
|
+
|
|
59
|
+
collection = site.collections[collection_name]
|
|
60
|
+
return unless collection
|
|
61
|
+
|
|
62
|
+
# Configuration with defaults
|
|
63
|
+
layout = config['layout']
|
|
64
|
+
permalink_template = config['permalink'] || "/#{collection_name}/:slug"
|
|
65
|
+
title_template = config['title'] || ':name'
|
|
66
|
+
description_template = config['description'] || 'Browse our collection of :name.'
|
|
67
|
+
|
|
68
|
+
# Extract unique categories from documents
|
|
69
|
+
categories = {}
|
|
70
|
+
|
|
71
|
+
collection.docs.each do |doc|
|
|
72
|
+
category_value = dig_value(doc.data, field)
|
|
73
|
+
next unless category_value && !category_value.empty?
|
|
74
|
+
|
|
75
|
+
category_slug = slugify(category_value)
|
|
76
|
+
next if categories.key?(category_slug)
|
|
77
|
+
|
|
78
|
+
# Format category name: titleize
|
|
79
|
+
category_name = titleize(category_value)
|
|
80
|
+
|
|
81
|
+
# Apply templates
|
|
82
|
+
permalink = apply_template(permalink_template, category_name, category_slug)
|
|
83
|
+
title = apply_template(title_template, category_name, category_slug)
|
|
84
|
+
description = apply_template(description_template, category_name, category_slug)
|
|
85
|
+
|
|
86
|
+
categories[category_slug] = {
|
|
87
|
+
'slug' => category_slug,
|
|
88
|
+
'name' => category_name,
|
|
89
|
+
'title' => title,
|
|
90
|
+
'description' => description,
|
|
91
|
+
'permalink' => permalink
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Generate a page for each category
|
|
96
|
+
categories.each do |slug, data|
|
|
97
|
+
page = DynamicCategoryPage.new(site, layout, data, collection_name)
|
|
98
|
+
site.pages << page
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
Jekyll.logger.info "DynamicPages:", "Generated #{categories.size} category pages for '#{collection_name}'"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Dig into nested hash using dot notation (e.g., "recipe.cuisine")
|
|
105
|
+
def dig_value(hash, field)
|
|
106
|
+
keys = field.split('.')
|
|
107
|
+
value = hash
|
|
108
|
+
keys.each do |key|
|
|
109
|
+
return nil unless value.is_a?(Hash)
|
|
110
|
+
value = value[key]
|
|
111
|
+
end
|
|
112
|
+
value.is_a?(String) ? value : nil
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def slugify(str)
|
|
116
|
+
str.to_s.downcase.strip.gsub(/[^\w\s-]/, '').gsub(/[\s_]+/, '-')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def titleize(str)
|
|
120
|
+
str.to_s.split(/[\s_-]+/).map(&:capitalize).join(' ')
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def apply_template(template, name, slug)
|
|
124
|
+
template.gsub(':name', name).gsub(':slug', slug)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Custom page class for dynamically generated category pages
|
|
129
|
+
class DynamicCategoryPage < Page
|
|
130
|
+
def initialize(site, layout, data, collection_name)
|
|
131
|
+
@site = site
|
|
132
|
+
@base = site.source
|
|
133
|
+
@dir = ''
|
|
134
|
+
@name = "#{data['slug']}.html"
|
|
135
|
+
|
|
136
|
+
self.process(@name)
|
|
137
|
+
self.data = {
|
|
138
|
+
'layout' => layout,
|
|
139
|
+
'title' => data['title'],
|
|
140
|
+
'description' => data['description'],
|
|
141
|
+
'category_slug' => data['slug'],
|
|
142
|
+
'category_name' => data['name'],
|
|
143
|
+
'collection_name' => collection_name,
|
|
144
|
+
'permalink' => data['permalink'],
|
|
145
|
+
'meta' => {
|
|
146
|
+
'title' => "#{data['title']} - #{site.config.dig('brand', 'name') || site.config['title']}",
|
|
147
|
+
'description' => data['description']
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Limit Collections Generator
|
|
2
|
+
# Limits the number of documents in collections during development for faster builds
|
|
3
|
+
#
|
|
4
|
+
# Usage in _config.dev.yml:
|
|
5
|
+
# limit_collections:
|
|
6
|
+
# recipes: 50
|
|
7
|
+
# products: 20
|
|
8
|
+
#
|
|
9
|
+
# By default, uses a seeded random sample for diverse selection across categories.
|
|
10
|
+
# To disable randomization and take first N documents:
|
|
11
|
+
# limit_collections:
|
|
12
|
+
# recipes: 50
|
|
13
|
+
# products: 20
|
|
14
|
+
# randomize: false
|
|
15
|
+
#
|
|
16
|
+
# Run Jekyll with: bundle exec jekyll serve --config _config.yml,_config.dev.yml
|
|
17
|
+
|
|
18
|
+
module Jekyll
|
|
19
|
+
class LimitCollectionsGenerator < Generator
|
|
20
|
+
safe true
|
|
21
|
+
priority :highest # Run before other generators
|
|
22
|
+
|
|
23
|
+
def generate(site)
|
|
24
|
+
limits = site.config['limit_collections']
|
|
25
|
+
return unless limits.is_a?(Hash)
|
|
26
|
+
|
|
27
|
+
# Check if randomization is disabled (default: true)
|
|
28
|
+
randomize = limits.fetch('randomize', true)
|
|
29
|
+
|
|
30
|
+
limits.each do |collection_name, limit|
|
|
31
|
+
# Skip the 'randomize' option itself
|
|
32
|
+
next if collection_name == 'randomize'
|
|
33
|
+
next unless limit.is_a?(Integer) && limit > 0
|
|
34
|
+
|
|
35
|
+
collection = site.collections[collection_name]
|
|
36
|
+
next unless collection
|
|
37
|
+
|
|
38
|
+
original_count = collection.docs.size
|
|
39
|
+
next if original_count <= limit
|
|
40
|
+
|
|
41
|
+
if randomize
|
|
42
|
+
# Use a seeded random for repeatable but diverse sampling
|
|
43
|
+
# Seed based on collection name so it's consistent across rebuilds
|
|
44
|
+
rng = Random.new(collection_name.hash.abs)
|
|
45
|
+
sampled_docs = collection.docs.shuffle(random: rng).first(limit)
|
|
46
|
+
collection.docs.replace(sampled_docs)
|
|
47
|
+
Jekyll.logger.info "LimitCollections:", "Limited '#{collection_name}' from #{original_count} to #{limit} documents (random sample)"
|
|
48
|
+
else
|
|
49
|
+
# Take first N documents in order
|
|
50
|
+
collection.docs.replace(collection.docs.first(limit))
|
|
51
|
+
Jekyll.logger.info "LimitCollections:", "Limited '#{collection_name}' from #{original_count} to #{limit} documents"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Parallel Build Generator
|
|
2
|
+
# Speeds up Jekyll builds by rendering pages and documents in parallel
|
|
3
|
+
#
|
|
4
|
+
# This runs as a Generator with :lowest priority to ensure it processes
|
|
5
|
+
# all pages AFTER other generators (like DynamicPages) have created them.
|
|
6
|
+
#
|
|
7
|
+
# Configuration in _config.yml:
|
|
8
|
+
#
|
|
9
|
+
# parallel_build:
|
|
10
|
+
# enabled: true # Enable/disable parallel builds (default: true)
|
|
11
|
+
# threads: 8 # Number of threads (default: number of CPU cores)
|
|
12
|
+
# min_items: 1 # Minimum items before parallelizing (default: 1)
|
|
13
|
+
#
|
|
14
|
+
# Note: Parallel builds work best with CPU-bound rendering.
|
|
15
|
+
# Some Liquid tags may not be thread-safe - if you encounter issues,
|
|
16
|
+
# disable with `parallel_build: false` or `parallel_build.enabled: false`
|
|
17
|
+
|
|
18
|
+
require 'parallel'
|
|
19
|
+
|
|
20
|
+
module Jekyll
|
|
21
|
+
class ParallelBuildGenerator < Generator
|
|
22
|
+
safe true
|
|
23
|
+
priority :lowest # Run AFTER all other generators
|
|
24
|
+
|
|
25
|
+
def generate(site)
|
|
26
|
+
config = site.config['parallel_build']
|
|
27
|
+
|
|
28
|
+
# Handle both `parallel_build: false` and `parallel_build.enabled: false`
|
|
29
|
+
if config == false
|
|
30
|
+
Jekyll.logger.info "ParallelBuild:", "Disabled via config"
|
|
31
|
+
return
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
config = {} if config.nil? || config == true
|
|
35
|
+
return unless config.fetch('enabled', true)
|
|
36
|
+
|
|
37
|
+
threads = config.fetch('threads', Parallel.processor_count)
|
|
38
|
+
min_items = config.fetch('min_items', 1)
|
|
39
|
+
|
|
40
|
+
# Render documents in parallel (posts, collections)
|
|
41
|
+
render_documents_parallel(site, threads, min_items)
|
|
42
|
+
|
|
43
|
+
# Render pages in parallel
|
|
44
|
+
render_pages_parallel(site, threads, min_items)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def render_documents_parallel(site, threads, min_items)
|
|
50
|
+
# Collect all documents that need rendering
|
|
51
|
+
documents = site.collections.flat_map do |_name, collection|
|
|
52
|
+
collection.docs.select { |doc| doc.respond_to?(:render) && !doc.data['rendered_parallel'] }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
return if documents.size < min_items
|
|
56
|
+
|
|
57
|
+
Jekyll.logger.info "ParallelBuild:", "Rendering #{documents.size} documents with #{threads} threads..."
|
|
58
|
+
|
|
59
|
+
start_time = Time.now
|
|
60
|
+
|
|
61
|
+
# Pre-render: prepare payload and info for each document
|
|
62
|
+
# We need to do the actual Liquid rendering in parallel
|
|
63
|
+
Parallel.each(documents, in_threads: threads) do |doc|
|
|
64
|
+
begin
|
|
65
|
+
# Mark as rendered to avoid double-rendering
|
|
66
|
+
doc.data['rendered_parallel'] = true
|
|
67
|
+
|
|
68
|
+
# Render content through Liquid
|
|
69
|
+
if doc.content && !doc.content.empty?
|
|
70
|
+
payload = site.site_payload
|
|
71
|
+
info = {
|
|
72
|
+
filters: [Jekyll::Filters],
|
|
73
|
+
registers: {
|
|
74
|
+
site: site,
|
|
75
|
+
page: doc.to_liquid
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Parse and render Liquid template
|
|
80
|
+
template = site.liquid_renderer.file(doc.path).parse(doc.content)
|
|
81
|
+
doc.content = template.render!(payload, info)
|
|
82
|
+
end
|
|
83
|
+
rescue => e
|
|
84
|
+
Jekyll.logger.warn "ParallelBuild:", "Error rendering #{doc.relative_path}: #{e.message}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
elapsed = Time.now - start_time
|
|
89
|
+
Jekyll.logger.info "ParallelBuild:", "Documents rendered in #{elapsed.round(2)}s"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def render_pages_parallel(site, threads, min_items)
|
|
93
|
+
# Get all pages (including dynamically generated ones without content)
|
|
94
|
+
pages = site.pages.reject { |page| page.data['rendered_parallel'] }
|
|
95
|
+
|
|
96
|
+
return if pages.size < min_items
|
|
97
|
+
|
|
98
|
+
Jekyll.logger.info "ParallelBuild:", "Rendering #{pages.size} pages with #{threads} threads..."
|
|
99
|
+
|
|
100
|
+
start_time = Time.now
|
|
101
|
+
|
|
102
|
+
Parallel.each(pages, in_threads: threads) do |page|
|
|
103
|
+
begin
|
|
104
|
+
page.data['rendered_parallel'] = true
|
|
105
|
+
|
|
106
|
+
# Only render if there's content to process
|
|
107
|
+
if page.content && !page.content.empty?
|
|
108
|
+
payload = site.site_payload
|
|
109
|
+
info = {
|
|
110
|
+
filters: [Jekyll::Filters],
|
|
111
|
+
registers: {
|
|
112
|
+
site: site,
|
|
113
|
+
page: page.to_liquid
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
template = site.liquid_renderer.file(page.path).parse(page.content)
|
|
118
|
+
page.content = template.render!(payload, info)
|
|
119
|
+
end
|
|
120
|
+
rescue => e
|
|
121
|
+
Jekyll.logger.warn "ParallelBuild:", "Error rendering #{page.name}: #{e.message}"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
elapsed = Time.now - start_time
|
|
126
|
+
Jekyll.logger.info "ParallelBuild:", "Pages rendered in #{elapsed.round(2)}s"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/jekyll-uj-powertools.rb
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
# Libraries
|
|
2
2
|
require "jekyll"
|
|
3
|
+
require "parallel"
|
|
3
4
|
|
|
4
5
|
module Jekyll
|
|
5
6
|
# Load Filters
|
|
6
7
|
require_relative "filters/main"
|
|
7
8
|
|
|
8
9
|
# Load Generators
|
|
10
|
+
require_relative "generators/limit-collections"
|
|
9
11
|
require_relative "generators/inject-properties"
|
|
10
12
|
require_relative "generators/blog-taxonomy"
|
|
13
|
+
require_relative "generators/dynamic-pages"
|
|
11
14
|
|
|
12
15
|
# Load Hooks
|
|
13
16
|
require_relative "hooks/inject-properties"
|
|
14
17
|
require_relative "hooks/markdown-images"
|
|
18
|
+
require_relative "hooks/parallel-build"
|
|
15
19
|
|
|
16
20
|
# Load Tags
|
|
17
21
|
require_relative "tags/external"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-uj-powertools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ITW Creative Works
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: jekyll
|
|
@@ -86,6 +85,20 @@ dependencies:
|
|
|
86
85
|
- - ">="
|
|
87
86
|
- !ruby/object:Gem::Version
|
|
88
87
|
version: '0'
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: ostruct
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0'
|
|
95
|
+
type: :development
|
|
96
|
+
prerelease: false
|
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
89
102
|
- !ruby/object:Gem::Dependency
|
|
90
103
|
name: nokogiri
|
|
91
104
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -100,6 +113,20 @@ dependencies:
|
|
|
100
113
|
- - ">="
|
|
101
114
|
- !ruby/object:Gem::Version
|
|
102
115
|
version: '1.17'
|
|
116
|
+
- !ruby/object:Gem::Dependency
|
|
117
|
+
name: parallel
|
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '1.20'
|
|
123
|
+
type: :runtime
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '1.20'
|
|
103
130
|
description: jekyll-uj-powertools provides a powerful set of utilities for Jekyll,
|
|
104
131
|
including functions to remove ads from strings and escape JSON characters.
|
|
105
132
|
email:
|
|
@@ -115,10 +142,13 @@ files:
|
|
|
115
142
|
- jekyll-uj-powertools.gemspec
|
|
116
143
|
- lib/filters/main.rb
|
|
117
144
|
- lib/generators/blog-taxonomy.rb
|
|
145
|
+
- lib/generators/dynamic-pages.rb
|
|
118
146
|
- lib/generators/inject-properties.rb
|
|
147
|
+
- lib/generators/limit-collections.rb
|
|
119
148
|
- lib/helpers/variable_resolver.rb
|
|
120
149
|
- lib/hooks/inject-properties.rb
|
|
121
150
|
- lib/hooks/markdown-images.rb
|
|
151
|
+
- lib/hooks/parallel-build.rb
|
|
122
152
|
- lib/jekyll-uj-powertools.rb
|
|
123
153
|
- lib/tags/external.rb
|
|
124
154
|
- lib/tags/fake_comments.rb
|
|
@@ -140,7 +170,6 @@ homepage: https://github.com/itw-creative-works/jekyll-uj-powertools
|
|
|
140
170
|
licenses:
|
|
141
171
|
- MIT
|
|
142
172
|
metadata: {}
|
|
143
|
-
post_install_message:
|
|
144
173
|
rdoc_options: []
|
|
145
174
|
require_paths:
|
|
146
175
|
- lib
|
|
@@ -155,8 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
155
184
|
- !ruby/object:Gem::Version
|
|
156
185
|
version: '0'
|
|
157
186
|
requirements: []
|
|
158
|
-
rubygems_version:
|
|
159
|
-
signing_key:
|
|
187
|
+
rubygems_version: 4.0.3
|
|
160
188
|
specification_version: 4
|
|
161
189
|
summary: A powerful set of utilities for Jekyll
|
|
162
190
|
test_files: []
|