diff --git a/lib/filters/webpack.rb b/lib/filters/webpack.rb new file mode 100644 index 000000000..799db8bfc --- /dev/null +++ b/lib/filters/webpack.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +## +# Compiles a JavaScript / TypeScript asset with webpack. +class Nanoc::Filter::Webpack < Nanoc::Filter + EXTNAMES = [".jsx", ".js", ".tsx", ".ts"] + include FileUtils + + identifier :webpack + type :text + always_outdated + + def run(content, options = {}) + file, dir = temp!(content, extname(item.identifier.to_s)) + basename = basename_for(item.identifier.to_s) + run_webpack(options.dup.delete(:exe) || "webpack", file.path, basename) + File.read(File.join(dir, basename)) + .tap { + file.tap(&:unlink).close + rm_rf(dir) + } + end + + private + + def basename_for(path) + File.basename path.sub(/#{Regexp.escape(extname(path))}\z/) { + EXTNAMES.include?(extname(path)) ? ".js" : nil + } + end + + def extname(path) + File.extname(path) + end + + def run_webpack(webpack_bin, path, basename) + system "node", + webpack_bin, + "--entry", path, + "--output-path", File.dirname(path), + "--output-filename", basename + exit! unless $?.success? + end + + def temp!(content, extname) + dir = File.join(Dir.getwd, "tmp", "webpack") + rm_rf(dir) + mkdir_p(dir) + file = Tempfile.new(["webpack", extname], dir) + file.write(content) + [file.tap(&:flush), dir] + end +end