jekyll-minify-js 0.2.1 → 0.2.12

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.
@@ -1,96 +1,129 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jekyll'
4
- require 'fileutils'
5
- require 'terser'
3
+ require "jekyll"
4
+ require "json"
5
+ require "open3"
6
+ require "pathname"
6
7
 
7
- require_relative 'version'
8
- require_relative 'color'
8
+ require_relative "version"
9
9
 
10
- # module Jekyll
11
10
  module Jekyll
12
- # module Jekyll::MinifyJs
11
+ # Minifies JavaScript assets after Jekyll finishes writing the site.
12
+ #
13
+ # The plugin reads files from a configured entry directory, invokes the
14
+ # bundled Node-based terser wrapper, and writes the compiled assets into the
15
+ # destination site output.
13
16
  module MinifyJs
14
- # class Jekyll::MinifyJs:TerserGenerator
17
+ # Runs JavaScript minification from Jekyll's post-write lifecycle.
18
+ #
19
+ # The generator itself does not perform work during the normal generation
20
+ # phase. Instead, {run} is invoked from a `:post_write` hook so Jekyll does
21
+ # not overwrite the generated minified files.
15
22
  class TerserGenerator < Jekyll::Generator
16
23
  safe true
17
24
  priority :low
18
25
 
26
+ # Declares the generator without doing work during the normal build phase.
27
+ #
28
+ # @param _site [Jekyll::Site] the site being generated
29
+ # @return [void]
19
30
  def generate(_site)
20
31
  # Work is done in the :post_write hook to avoid Jekyll overwriting outputs.
21
32
  end
22
33
 
23
- def self.run(site) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
24
- config = site.config['minify_js'] || {}
25
- # disable to skip minification
26
- return if config['enable'] && config['enable'] == false
27
-
28
- started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
29
- # Build options from config
30
- compress_opt = config['compress'] || true
31
- mangle_opt = config['mangle'] || true
32
- source_map_enabled = config['source_map'] || true
33
-
34
- Jekyll.logger.info ''
35
- Jekyll.logger.info set_color(96, "Running Jekyll MinifyJs v#{Jekyll::MinifyJs::VERSION}", 1)
36
-
37
- entry_dir = config['entry_dir'] || 'js'
38
- out_dir = config['output_dir'] || 'js'
34
+ # Merges the plugin configuration with defaults.
35
+ #
36
+ # @param site [Jekyll::Site] the current site instance
37
+ # @return [Hash] the merged `minify_js` configuration
38
+ def self.minify_js_config(site)
39
+ default_config = {
40
+ "enabled" => true,
41
+ "entry_dir" => "js",
42
+ "output_dir" => "js",
43
+ "terser_opts" => {
44
+ "source_map" => true,
45
+ "compress" => true
46
+ }
47
+ }
48
+ site.config["minify_js"] = default_config.merge(site.config["minify_js"] || {})
49
+ end
39
50
 
40
- if config['entry_dir']
41
- Jekyll.logger.info "Entry : #{File.join(site.source, config['entry_dir'])}"
42
- else
43
- Jekyll.logger.info "Entry : No entry_dir found, look in #{File.join(site.source, 'js')}"
44
- end
51
+ # Runs the Node-based terser wrapper for one JavaScript source string.
52
+ #
53
+ # @param code [String] the JavaScript source to minify
54
+ # @param ts_opts [Hash, nil] terser options passed to the wrapper
55
+ # @return [Hash] the parsed JSON response from the wrapper
56
+ # @raise [RuntimeError] if the wrapper process exits unsuccessfully
57
+ def self.run_terser(code, ts_opts)
58
+ script_path = File.expand_path("../assets/index.js", __dir__)
59
+ input = JSON.generate({
60
+ code: code,
61
+ opts: ts_opts
62
+ }.compact)
63
+ stdout, stderr, status = Open3.capture3("node", script_path, stdin_data: input)
64
+ raise "Minify JS failed: #{stderr}" unless status.success?
65
+
66
+ JSON.parse(stdout)
67
+ end
45
68
 
46
- if config['output_dir']
47
- Jekyll.logger.info "Output : #{File.join(site.dest, config['output_dir'])}"
48
- else
49
- Jekyll.logger.info "Output : No output_dir found, write to #{File.join(site.dest, 'js')}"
69
+ # Finds JavaScript files in the configured entry directory.
70
+ #
71
+ # @param site [Jekyll::Site] the current site instance
72
+ # @param entry [String, nil] the source directory relative to `site.source`
73
+ # @return [Array<String>, nil] matching absolute file paths, or `nil` when
74
+ # no entry directory is configured or no files are found
75
+ def self.entry_js_files(site, entry)
76
+ entry_full = File.join(site.source, entry)
77
+ js_files = Dir.glob(File.join(entry_full, "**", "*.js"))
78
+ if Dir.exist?(entry_full) && js_files.empty?
79
+ Jekyll.logger.warn "MinifyJs:",
80
+ "No JavaScript files found in #{entry_full}."
50
81
  end
82
+ return if entry.nil? || js_files.empty?
51
83
 
52
- entry_dir_full = File.join(site.source, entry_dir)
53
- out_dir_full = File.join(site.dest, out_dir)
54
- js_files = Dir.glob(File.join(entry_dir_full, '**', '*.js'))
84
+ js_files
85
+ end
55
86
 
56
- Jekyll.logger.warn 'MinifyJs:', "Entry directory not found: #{entry_dir_full}" unless Dir.exist?(entry_dir_full)
57
- if Dir.exist?(entry_dir_full) && js_files.empty?
58
- Jekyll.logger.info 'MinifyJs:',
59
- "No JavaScript files found in #{entry_dir_full}"
60
- end
87
+ # Resolves the output directory for minified assets.
88
+ #
89
+ # @param site [Jekyll::Site] the current site instance
90
+ # @param out [String, nil] the configured output directory
91
+ # @param entry [String] the configured entry directory
92
+ # @return [String] the absolute destination directory inside `site.dest`
93
+ def self.output_dir(site, out, entry)
94
+ out ? File.join(site.dest, out) : File.join(site.dest, entry)
95
+ end
61
96
 
62
- FileUtils.mkdir_p(out_dir_full)
97
+ # Minifies every JavaScript file configured for the site.
98
+ #
99
+ # Files are written into the resolved output directory. If minification of
100
+ # an individual file fails, the original file is copied instead.
101
+ #
102
+ # @param site [Jekyll::Site] the current site instance
103
+ # @return [void]
104
+ def self.run(site) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
105
+ Jekyll.logger.info "Running jekyll-minify-js v#{Jekyll::MinifyJs::VERSION}"
106
+ mini_js_config = minify_js_config(site)
107
+ entry_dir = mini_js_config["entry_dir"]
108
+ nil if (mini_js_config["enable"] && mini_js_config["enable"] == false) || entry_dir.nil?
109
+ out_dir = output_dir(site, mini_js_config["output_dir"], entry_dir)
110
+ ts_opts = mini_js_config["terser_opts"]
111
+ entry_dir_full = File.join(site.source, entry_dir)
112
+ js_files = entry_js_files(site, entry_dir)
63
113
 
64
114
  js_files.each do |src|
65
- rel = src.sub(/\A#{Regexp.escape(entry_dir_full + File::SEPARATOR)}/, '')
66
- out = File.join(out_dir_full, rel)
67
- map_name = "#{File.basename(out)}.map"
68
-
69
- begin
70
- src_content = File.open(src, 'r:BOM|UTF-8', &:read)
71
- options = {}
72
- options[:compress] = compress_opt
73
- options[:mangle] = mangle_opt
74
- if source_map_enabled
75
- options[:source_map] =
76
- { filename: File.basename(src), output_filename: File.basename(out), sources_content: true,
77
- url: map_name }
78
- compiled, map = Terser.compile_with_map(src_content, options)
79
- else
80
- compiled = Terser.compile(src_content, options)
81
- map = nil
82
- end
83
- compiled += "\n//# sourceMappingURL=#{map_name}\n" unless compiled.include?('sourceMappingURL')
84
- File.write(out, compiled)
85
- File.write("#{out}.map", map) if map
86
- rescue StandardError => e
87
- Jekyll.logger.warn 'Terser:', "ruby terser failed for #{rel}: #{e.message}; copying original"
88
- FileUtils.cp(src, out)
89
- end
115
+ rel = src.sub(/\A#{Regexp.escape(entry_dir_full + File::SEPARATOR)}/, "")
116
+ out = File.join(out_dir, rel)
117
+ src_content = File.read(src)
118
+ result = run_terser(src_content, ts_opts)
119
+ compiled = result["compiled"]
120
+ source_map = result["source_map"]
121
+ File.write(out, compiled)
122
+ File.write("#{out}.map", source_map) if source_map
123
+ rescue StandardError => e
124
+ Jekyll.logger.warn "jekyll-minify-js:", "failed to minify for #{rel}: #{e.message}; copying original"
125
+ FileUtils.cp(src, out)
90
126
  end
91
-
92
- elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
93
- Jekyll.logger.info set_color(92, format('Done in %.2fs', elapsed), 1)
94
127
  end
95
128
  end
96
129
  end
data/lib/version.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jekyll
4
+ # Namespace for the jekyll-minify-js plugin.
4
5
  module MinifyJs
5
- VERSION = '0.2.1'
6
+ # Current gem version.
7
+ #
8
+ # @return [String]
9
+ VERSION = "0.2.12"
6
10
  end
7
11
  end
metadata CHANGED
@@ -1,28 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-minify-js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
- - Pho Thin Maung
7
+ - phothinmg
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: fileutils
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '1.8'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '1.8'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: jekyll
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -38,32 +24,37 @@ dependencies:
38
24
  - !ruby/object:Gem::Version
39
25
  version: '4.4'
40
26
  - !ruby/object:Gem::Dependency
41
- name: terser
27
+ name: open3
42
28
  requirement: !ruby/object:Gem::Requirement
43
29
  requirements:
44
- - - "~>"
30
+ - - ">="
45
31
  - !ruby/object:Gem::Version
46
- version: '1.2'
32
+ version: 0.2.1
47
33
  type: :runtime
48
34
  prerelease: false
49
35
  version_requirements: !ruby/object:Gem::Requirement
50
36
  requirements:
51
- - - "~>"
37
+ - - ">="
52
38
  - !ruby/object:Gem::Version
53
- version: '1.2'
54
- email: phothinmg@disroot.org
39
+ version: 0.2.1
40
+ email:
41
+ - phothinmg@disroot.org
55
42
  executables: []
56
43
  extensions: []
57
44
  extra_rdoc_files: []
58
45
  files:
59
46
  - LICENSE.txt
60
- - lib/color.rb
47
+ - README.md
48
+ - assets/index.js
49
+ - assets/index.js.map
61
50
  - lib/jekyll-minify-js.rb
62
51
  - lib/version.rb
63
52
  homepage: https://github.com/phothinmg/jekyll-minify-js
64
53
  licenses:
65
54
  - MIT
66
55
  metadata:
56
+ homepage_uri: https://github.com/phothinmg/jekyll-minify-js
57
+ changelog_uri: https://github.com/phothinmg/jekyll-minify-js/blob/main/CHANGELOG.md
67
58
  rubygems_mfa_required: 'true'
68
59
  rdoc_options: []
69
60
  require_paths:
@@ -72,14 +63,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
63
  requirements:
73
64
  - - ">="
74
65
  - !ruby/object:Gem::Version
75
- version: '3.1'
66
+ version: 3.2.0
76
67
  required_rubygems_version: !ruby/object:Gem::Requirement
77
68
  requirements:
78
69
  - - ">="
79
70
  - !ruby/object:Gem::Version
80
71
  version: '0'
81
72
  requirements: []
82
- rubygems_version: 4.0.11
73
+ rubygems_version: 4.0.15
83
74
  specification_version: 4
84
- summary: Jekyll plugin for Minify Js.
75
+ summary: Jekyll plugin for Minify Js
85
76
  test_files: []
data/lib/color.rb DELETED
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- def set_color(index, content, weight = 0)
4
- "\e[#{weight};#{index}m#{content}\e[0m "
5
- end