Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Minify Ruby Code

Koichi ITO
August 04, 2024

Minify Ruby Code

Koichi ITO

August 04, 2024
Tweet

More Decks by Koichi ITO

Other Decks in Programming

Transcript

  1. w ൃද࣌ͷ࠷৽ͷ3VCZͰ͋ΔEFWͱɺ 1SJTNͷ࣍ͷ։ൃ൛Λલఏʹͯ͠·͢ ຊτʔΫʹ͓͚Δόʔδϣϯ $ ruby -rprism -ve 'p Prism::VERSION'

    ruby 3.4.0dev (2024-07-30T06:31:58Z master 1870505f47) [x86_64-darwin23] "0.30.0" # ݫີʹ͸0.31.0޲͚ͷ։ൃ൛ rbenv install 3.4-devͳͲͰ͓खݩʹΠϯετʔϧ
  2. +BWB4DSJQUઌഐͰͷ.JOJGZྫ function greet(name) { console.log(`Hello! ${name}`); } greet("Osaka RubyKaigi 04");

    // Hello, Osaka RubyKaigi 04! HSFFUKT $ npx terser greet.js function greet(name){console.log(`Hello! ${name}`)}\ greet("Osaka RubyKaigi 04"); .JOJGZ͢Δ εϖʔεͷ౎߹ʹ͖࣮ͭࡍ͸ߦ
  3. w ಈ࡞͢ΔͨΊʹඞཁͷͳ͍εϖʔεɺվߦɺ ίϝϯτɺηϛίϩϯͷྨΛআڈ͢Δ w ϨΠΞ΢τ΍ߦؒΛ่͠ɺݟͨ໨Λ6HMJGZ͢Δ w ʮಈ࡞͢Δ͖Ε͍ͳίʔυʯͱҟͳΔՁ஋؍ ಈ࡞͢Δ୹͍ίʔυ $ npx

    terser greet.js | tee >(node) function greet(name){console.log(`Hello! ${name}`)} greet("Osaka RubyKaigi 04"); Hello! Osaka RubyKaigi 04 UFSTFSͷ݁ՌΛϓϩηεஔ׵Ͱ࣮ߦͨ݁͠Ռ
  4. w ໝ૝ͦͷɻSVCZXBTNͷίʔυͰ֎෦Ϧιʔ εΛཁٻͨ͠ࡍʹɺ*4FRͳͲͷதؒදݱͰͳ͍ QMBJOͳ3VCZίʔυͷωοτϫʔΫసૹྔݮʁ w ໝ૝ͦͷɻΤοδίϯϐϡʔςΟϯάͰɺΤο δαʔόʔ $%/ ΍ΤοδσόΠε *P5

    ΁ͷ ίϯςϯπ΍σʔλͷ഑෍ʹ͓͍ͯ༗༻ʁ ະདྷͷ͓࢓ࣄ3VCZͩͱͲ͏ʁ NJOJGZ͸1JDP3VCZͷϝϞϦ࡟ݮʹ࢖͑Δ͸ͣͳͷͰ஫໨͍ͯ͠·͢ɻ IUUQTYDPNIBTVNJLJOTUBUVT
  5. w γϯϘϧΛҾ਺ʹͨ͠ϝιουݺͼग़͠ τʔΫϯྻͷαϯϓϧ puts :hello [:IDENTIFIER, :SYMBOL_BEGIN, :IDENTIFIER, :EOF] puts

    : hello %w(foo) [:PERCENT_LOWER_W, :STRING_CONTENT, :STRING_END, :EOF] w ཁૉͻͱͭͷXϦςϥϧ %w( foo )
  6. ߏจ໦ͷαϯϓϧ $ ruby -rprism -e 'p Prism.parse("42").value' @ ProgramNode (location:

    (1,0)-(1,2)) ├── flags: ∅ ├── locals: [] └── statements: @ StatementsNode (location: (1,0)-(1,2)) ├── flags: ∅ └── body: (length: 1) └── @ IntegerNode (location: (1,0)-(1,2)) ├── flags: newline, static_literal, decimal └── value: 42 Prism.parseͰPrism::ParseResultΛಘΔ
  7. w LexResult.valueͰτʔΫϯΛද͢ Prism::TokenͱMFYTUBUF CJU஋ ͷ഑ྻ֫ಘ w MFYTUBUF஋͸Լهࢀর ຊฤະ࢖༻ʹׂ͖ͭѪ 1SJTN-FY3FTVMU require

    'prism' result = Prism.lex('puts :hello') result.value.class #=> Array result.value.first #=> [#<Prism::Token>, 32] IUUQTHJUIVCDPNSVCZQSJTNCMPCWJODMVEFQSJTNQBSTFSI--
  8. w LexResult.valueͷ഑ྻͷୈҰཁૉ Prism::Token͸ܕɺ஋ɺҐஔ৘ใΛ࣋ͭ 1SJTN5PLFO result = Prism.lex('puts :hello') token, _state

    = result.value.first token.class #=> Prism::Token token.type #=> :IDENTIFIER token.value #=> "puts" token.location.class #=> Prism::Location
  9. w ParseToken.locationͰτʔΫϯͷҐஔ ৘ใΛ࣋ͭPrism::LocationΛಘΒΕΔ 1SJTN-PDBUJPO result = Prism.lex('puts :hello') token, _state

    = result.value.first location = token.location location.first_line #=> 1 location.start_offset #=> 0 location.length #=> 4
  10. τʔΫϯॲཧͷఆੴαϯϓϧ tokens = Prism.lex(source).value tokens.each_cons(2)do|(token,_),(next_token,_)| case token.type when :COMMENT #

    do_something when :IDENTIFIER # do_something end prev_token = token end FBDI@DPOT  Ͱ࣍ͷτʔΫϯ৘ใΛઌಡΈ͢Δ QSFW@UPLFOͰલͷτʔΫϯ৘ใΛอ͓࣋ͯ͘͠ ͜ͷ͋ͱ঺հ͢Δ.JOJGZ3VCZ͸͜ͷͭ͘Γ UPLFOUZQFͷछྨͰॲཧΛ൑ผ͢Δ ࠨ͔Βӈ΁ͷτʔΫϯྻͷϧʔϓ
  11. w {}ϕʔεͷߏจͱͳΔ+BWB4DSJQUͰ͸ྫ͑͹ functionΛҰߦͰෳ਺ఆٛͰ͖Δ +BWB4DSJQUͷϫϯϥΠφʔʹֶͿ $ cat example.js | tee >(npx

    terser) function foo() { console.log(bar()); } function bar() { 42; } function foo(){console.log(bar())}function bar(){42} εϖʔεɺηϛίϩϯෆཁ ಡΈ΍͢͞ͷվߦΛ͢Δ
  12. Prism.lex͸&SSPS5PMFSBODFʹͳͬͯΔ &SSPS5PMFSBODF $ ruby -ce 'cond(arg)?x:y' # εϖʔεͳ͠ѹॖ͸ߏจΤϥʔͷྫ -e:1: syntax

    error, unexpected symbol literal, expecting 'do' or '{' or '(' cond(arg)?x:y ruby: compile error (SyntaxError) $ ruby -ce 'cond(arg)?x: y' # ͜ͷ৔߹:ͱyͷؒʹཁεϖʔε Syntax OK $ ruby -rprism -e "p Prism.lex('cond(arg)?x:y').value" [[#<Prism::Token:0x0000000104c87b70 @source=#<Prism::ASCIISource:0x000000011f7f5dd0 ͍ͭ͜ಈͧ͘ʂ
  13. w ͜ͷվߦ͕ͳ͘ͳͬͯ΋ߏจͱͯ͠ଥ౰Ͱ͋Δ w ηϛίϩϯͳ͠Ͱվߦ࡟আ͸Ͳ͜·ͰͰ͖Δʁ *(/03&%@/&8-*/&τʔΫϯ begin rescue CustomError=>e else ensure

    end ݩ͸όΠτ aOͷ৔߹ begin rescue CustomError=>e else ensure end *(/03&%@/&8-*/&ద༻ όΠτ begin rescue CustomError=>e;else ensure end ࢀߟผ్ηϛίϩϯஔ׵ όΠτ
  14. w ʮಈ࡞͢Δ͖Ε͍Ͱ͸ͳ ͍ίʔυʯ͕ຊτʔΫͷ ςʔϚͰ͢Α w .JOJGZͱ53*$,೴͸ີ઀ ʹؔ࿈͢ΔԾઆ w 53*$,ͷLJOBCB͞ Μ࡞඼ͷཧղʹ͚ۙͮΔʁ

    ͜ͷτʔΫϯ͔ΒಘΒΕΔֶͼ IUUQTHJUIVCDPNUSJDUSJDLCMPCNBTUFSLJOBCBFOUSZSC 53*$,໊࡞ͷͻͱͭ
  15. w BMJBTFRM ͕BMJBTFRM ͸ߏจΤϥʔ w GPP 'PP͕GPP 'PP͸ҙຯ͕มΘΔ w BSSBZ͕

    BSSBZ͸ߏจΤϥʔ w GPPX BCD ͕GPPX BCD ͸ҙຯ͕มΘΔ w GPPX BGPSC ͕GPPX BGPSC ͸ߏจΤϥʔ ݁߹ͯ͠͸͍͚ͳ͍γϦʔζͷҰ෦ unexpected char literal unexpected operator assignment unexpected ')'
  16. w ด͡Χοίલͷվߦ͸IGNORED_NEWLINEʹͰ͖Δ ͸͕ͣͩɺΧϯϚͳͩ͠ͱNEWLINEͱ͞ΕΔ ҙਤతͳ3JQQFSޓ׵ɺSVCZQSJTNࢀর  w ;΁ͷ୯७ͳஔ׵͸[foo, bar, baz;]ͷߏจΤϥʔ <ิ଍>୯७ͳηϛίϩϯஔ׵͸ෆՄ

    [ foo, bar, baz ] :BRACKET_LEFT_ARRAY,:IGNORED_NEWLINE :IDENTIFIER, :COMMA,:IGNORED_NEWLINE :IDENTIFIER, :COMMA,:IGNORED_NEWLINE :IDENTIFIER, :NEWLINE :BRACKET_RIGHT, :NEWLINE, :EOF
  17. վߦͷτʔΫϯॲཧ֓ཁ tokens.each(2) do |(token, _), (next_token, _)| case token.type when

    :IGNORED_NEWLINE # noop when :NEWLINE token_value = if next_token.type == :EOF token.value elsif CLOSING_DELIMITER_TYPES.include?(next_token.type) # noop else ';' end 104*9ͷΞϨ΁ͷOFXMJOFରԠ Ճ͑ͯɺdeffooͳͲ༧໿ޠ͕݁߹͠ͳ͍Α͏ͳॲཧΛผ్͍ͯ͠Δ > ^ͷτʔΫϯͷఆ਺ɻຊདྷ*(/03&%@/&8-*/&͔΋ͳύον
  18. IFSFEPDͷτʔΫϯॲཧ֓ཁ tokens.each(2) do |(token, _), (next_token, _)| case token.type when

    :HEREDOC_START @in_heredoc = true squiggly_heredoc = token.value.start_with?('<<~') # SNIP: <<'HEREDOC', <<"HEREDOC", <<`HEREDOC`΁ͷॲཧׂѪ when :HEREDOC_END heredoc_contents = @heredoc_content_tokens.join # SNIP: <<~΁ͷdedentॲཧΛׂѪ @minified_values << heredoc_contents @minified_values << (@string_quote == '`' ? '`' : '"') @heredoc_content_tokens.clear @in_heredoc = false IFSFEPDதͷτʔΫϯॲཧΛ༗ޮԽ IFSFEPDதͷτʔΫϯॲཧΛແޮԽ EFEFOUॲཧ͕ඞཁ͔ঢ়ଶΛ࣋ͨͤΔ IFSFEPD͸ແҹҎ֎ΫΥʔτ͕ͱ͓Γ IFSFEPDຊจͷτʔΫϯ஋ͷ഑ྻΛ݁߹
  19. ࠓޙͷ֦ுʹ޲͚ͨ஫ҙ఺ def m(a) bar unless cond end def m(a)bar unless

    cond end w Ҿ਺Χοί͋Γͷɺվߦ΍ηϛίϩϯͳ͠Ͱॻ͚ΔFOE͋Γͷ ϫϯϥΠφʔϝιουఆٛʹ͍ͭͯߟ͑Δ ಉ͡ߏจ໦
  20. # Original $ find . -name '*.rb' -type f -print0

    | \ xargs -0 wc -c | awk 'END{print $1}' 49825 # Original $ find . -name '*.rb' -type f -print0 | \ xargs -0 wc -c | awk 'END{print $1}' 49825 # Minify $ bundle exec rake minify $ find . -name '*.rb' -type f -print0 | \ xargs -0 wc -c | awk 'END{print $1}' 31598 # Original $ find . -name '*.rb' -type f -print0 | \ xargs -0 wc -c | awk 'END{print $1}' 49825 # Minify $ bundle exec rake minify $ find . -name '*.rb' -type f -print0 | \ xargs -0 wc -c | awk 'END{print $1}' 31598 # Ratio $ ruby -e 'p 31598 / 49825.0' 0.6341796287004515 .JOJGZͰͲΕ͘Β͍ݮΔʁ
  21. w MJC͸ όΠτ͔Β όΠτʹͳΓɺ TQFD͸ όΠτ͔Β όΠτʹ ͳΔ w ͭ·Γ࡟ݮ͞Εͨίʔυ͸34QFDͷํ͕ߴ͍

    w ࣮ફత ͱ͸ʁ ʹ͸ϓϩμΫτίʔυ΁ͷޮ Ռ͕ߴ͍ํ͕͍͍Μ͚ͩͲݱ࣮͸͜͏Β͍͠ ଌఆͱධՁΛ΋͏গ͠