Skip to content

Commit

Permalink
add cache to precompile mjml files in test env
Browse files Browse the repository at this point in the history
  • Loading branch information
bugloper committed Oct 1, 2024
1 parent 75102ad commit 6381643
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 19 deletions.
3 changes: 2 additions & 1 deletion lib/mjml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ module Mjml
:raise_render_exception,
:template_language,
:validation_level,
:use_mrml
:use_mrml,
:cache_mjml

mattr_writer :valid_mjml_binary

Expand Down
45 changes: 45 additions & 0 deletions lib/mjml/cache.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

module Mjml
class Cache
attr_reader :template_path

def initialize(template_path)
@template_path = template_path
end

# @yield [] -> String
# @return [String]
def cache(&block)
return yield if !Mjml.cache_mjml && block

cached_path = cached_file_path
if File.exist?(cached_path)
File.read(cached_path)
else
html_content = yield if block
File.write(cached_path, html_content)
html_content
end
end

private

def cached_file_path
File.join(cache_directory, "#{fingerprint}.html")
end

def fingerprint
full_path = File.join(Dir.pwd, 'app', 'views', "#{template_path}.mjml")
raise "Template file not found: #{full_path}" unless File.exist?(full_path)

Digest::SHA256.hexdigest(File.read(full_path))
end

def cache_directory
dir = File.join(Dir.pwd, 'tmp', 'mjml_cache')
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
dir
end
end
end
3 changes: 2 additions & 1 deletion lib/mjml/handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def call(template, source = nil)
compiled_source = compile_source(source, template)

parser_class = Mjml.use_mrml ? 'MrmlParser' : 'Parser'
template_path = template.virtual_path
# Per MJML v4 syntax documentation[0] valid/render'able document MUST start with <mjml> root tag
# If we get here and template source doesn't start with one it means
# that we are rendering partial named according to legacy naming convention (partials ending with '.mjml')
Expand All @@ -25,7 +26,7 @@ def call(template, source = nil)
#
# [0] - https://github.com/mjmlio/mjml/blob/master/doc/components_1.md#mjml
if /<mjml.*?>/i.match?(compiled_source)
"Mjml::#{parser_class}.new(begin;#{compiled_source};end).render.html_safe"
"Mjml::#{parser_class}.new('#{template_path}', begin;#{compiled_source};end).render.html_safe"
else
compiled_source
end
Expand Down
38 changes: 23 additions & 15 deletions lib/mjml/parser.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
# frozen_string_literal: true

require 'digest'
require_relative 'cache'

module Mjml
class Parser
class ParseError < StandardError; end

attr_reader :input
attr_reader :template_path, :input

# Create new parser
#
# @param input [String] The string to transform in html
def initialize(input)
# @param template_path [String] The path to the .mjml file
# @param input [String] The content of the .mjml file
def initialize(template_path, input)
raise Mjml.mjml_binary_error_string unless Mjml.valid_mjml_binary

@input = input
@template_path = template_path
@input = input
@with_cache = Cache.new(template_path)
end

# Render mjml template
# Render MJML template
#
# @return [String]
def render
in_tmp_file = Tempfile.open(['in', '.mjml']) do |file|
file.write(input)
file # return tempfile from block so #unlink works later
end
run(in_tmp_file.path)
rescue StandardError
raise if Mjml.raise_render_exception
@with_cache.cache do
in_tmp_file = Tempfile.open(['in', '.mjml']) do |file|
file.write(input)
file # return tempfile from block so #unlink works later
end
run(in_tmp_file.path)
rescue StandardError
raise if Mjml.raise_render_exception

''
ensure
in_tmp_file&.unlink
''
ensure
in_tmp_file&.unlink
end
end

# Exec mjml command
Expand Down
4 changes: 2 additions & 2 deletions test/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

describe Mjml::Parser do
let(:input) { mock('input') }
let(:parser) { Mjml::Parser.new(input) }
let(:parser) { Mjml::Parser.new('test_template', input) }

describe '#render' do
describe 'when exception is raised' do
Expand Down Expand Up @@ -42,7 +42,7 @@
expect(Mjml.beautify).must_equal(true)
expect(Mjml.minify).must_equal(false)
expect(Mjml.validation_level).must_equal('strict')
expect(Mjml.fonts).must_equal(nil)
assert_nil(Mjml.fonts)
end

it 'uses setup config' do
Expand Down
18 changes: 18 additions & 0 deletions test/views/test_template.mjml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<mjml owa="desktop">
<mj-body>
<mj-section>
<%= render partial: "user_header", formats: [:html] %>
</mj-section>

<mj-section>
<mj-column>
<mj-text>
<h2>We inform you about something</h2>
<p>
Please visit <a href="https://www.example.com">this link</a>
</p>
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>

0 comments on commit 6381643

Please sign in to comment.