Qiita / Qiita:Team における Markdown レンダリングの歴史

Qiita / Qiita:Team における Markdown レンダリングの歴史

Markdown Night 2017 Summer
https://connpass.com/event/63383/

520b23dc9027ee642ea39a4c273fed7b?s=128

Yuji Nakayama

August 29, 2017
Tweet

Transcript

  1. 2JJUB2JJUB5FBNʹ͓͚Δ .BSLEPXOϨϯμϦϯάͷྺ࢙ Yuji Nakayama @nkym37 @yujinakayama 

  2. None
  3. None
  4. None
  5. None
  6. None
  7. ࠷ॳ͸Q&AαʔϏεͩͬͨ

  8. None
  9. ࠷ॳ͸ MarkdownະରԠͩͬͨ

  10. ࠓ೔࿩͢͜ͱ .BSLEPXOυΩϡϝϯτΛϗετ͢Δ8FCαʔϏεΛӡ Ӧ͢Δ্Ͱ௚໘͖ͯͨ͠ɺ.BSLEPXOϨϯμϥʔपΓͷ టष͍ࣄ৘

  11. 2JJUBͷॳظͷ.BSLEPXOαϙʔτ ೥݄ 2JJUBϦϦʔεͷϲ݄ޙ 

  12. ॳظͷ2JJUBͷ.BSLEPXOϨϯμϥʔ w ࣮૷͸SFEDBSQFU ΧελϜϨϯμϥʔ w SFEDBSQFU͸$Ͱॻ͔Εͨ.BSLEPXOύʔαʔͷSVCZHFN w ౰࣌ͷ(JU)VC'MBWPSFE.BSLEPXOͷ࣮૷͸SFEDBSQFUͷ ϕʔεͰ͋ΔTVOEPXOΛϕʔεʹ͍ͯͨ͠ʢͱࢥΘΕΔʣ w

    ·ͩ$PNNPO.BSL͸ͳ͔ͬͨ
  13. class Qiita::Markdown::Renderer < Redcarpet::Render::HTML # ... end renderer = Qiita::Markdown::Renderer(

    filter_html: true, hard_wrap: true ) parser = Redcarpet::Markdown.new( renderer, autolink: true, fenced_code_blocks: true ) html = parser.render(markdown)
  14. ॳظͷ࢓༷ w ࢓༷తʹ͸(JU)VC'MBWPSFE.BSLEPXOʹد͍ͤͯͨ w BVUPMJOL63-ͬΆ͍จࣈྻΛࣗಈͰϦϯΫʹ w GFODFE@DPEF@CMPDLT```\nsome code\n``` w IBSE@XSBQ.BSLEPXOͷվߦͰ<br>ग़ྗ

    w ΧελϜϨϯμϥʔͰγϯλοΫεϋΠϥΠτ w ͷͪʹଧͪফ͠ઢ΍ςʔϒϧه๏ʹ΋ରԠ
  15. ϝϯγϣϯه๏ͷಋೖ ೥݄ @username 

  16. 2JJUB5FBNϦϦʔε ೥݄ αχλΠζͷϧʔϧ͕2JJUBͱएׯҟͳΔ 

  17. ֆจࣈͷαϙʔτ ೥݄ :tada: 

  18. qiita-markdown gem ೥݄ 

  19. qiita-markdown gem w IUNMQJQFMJOF SFEDBSQFU OPLPHJSJ w IUNMQJQFMJOF͸)5.-ॲཧͷ3VCZϑϨʔϜϫʔΫ w ίΞϨϯμϥʔͱͯ͠SFEDBSQFUΛ࢖͍ɺͦͷग़ྗʹର͠

    ͯෳ਺ͷϑΟϧλʔʹΑΔޙॲཧΛద༻ w 044Խ
  20. Redcarpet filter Emoji filter Syntax highlight filter Mention filter Markdown

    string HTML tree HTML tree HTML tree HTML tree HTML tree HTML tree HTML tree
  21. IUNMQJQFMJOFͷԿ͕خ͍͔͠ w ੹຿͝ͱʹϑΟϧλʔΛ෼͚ΒΕΔͷͰɺίʔυͷݟ௨͕͠ྑ͘ͳΔ w ϑΟϧλʔͷద༻ॱং͕໌֬ w جຊσʔλߏ଄ͱͯ͠OPLPHJSJͷ)5.-USFFΛ࠾༻͍ͯ͠ΔͨΊ )5.-ͷૢ࡞͕ݎ࿚ w ҎલͷϨϯμϥʔͰ͸Ұ෦ਖ਼نදݱΛ࢖͍ͬͯΔՕॴ͕͋ͬͨ

  22. ϢʔβʔͷաڈͷίϝϯτҰཡ ೥݄ 

  23. None
  24. None
  25. ίϝϯτҰཡΛදࣔ͢Δ w هࣄҰཡͳΒλΠτϧΛදࣔ͢Ε͹ྑ͍͕ɺίϝϯτʹ͸ λΠτϧ͕ͳ͍ͷͰɺຊจͷཁ໿Λදࣔ͢Δඞཁ͕͋Δ w ௕͗͢ΔίϝϯτશจΛදࣔͨ͘͠͸ͳ͍ w ཁ໿ͱͯ͠දࣔ͢Δͷ͕೉͍͠ɺෳࡶͳϚʔΫΞοϓΛऔ Γআ͖͍ͨ

  26. None
  27. Qiita::Markdown::SummaryProcessor w ϒϩοΫཁૉͷத਎͸࢒ͭͭ͠λάΛ࡟আ͢Δ͜ͱͰɺΠϯϥΠϯԽ •<p>foo<em>bar</em></p>ˠfoo<em>bar</em> w ςʔϒϧͷΑ͏ͳɺΠϯϥΠϯԽͯ͠΋ෳࡶ͗ͯ͢ҙຯΛͳ͞ͳ͍ཁ ૉ͸த਎͝ͱ࡟আ w )5.-ͷυΩϡϝϯτߏ଄Λߟྀͭͭ͠USVODBUF

  28. None
  29. ϝϯγϣϯͰ͖ͳ͍Ϣʔβʔ໰୊ ೥݄ 

  30. ϝϯγϣϯͰ͖ͳ͍ਓ͕͍ΔΜͰ͕͢ʜ

  31. @qiitan Markdown HTML <a href="/qiitan">@qiitan</a> @<strong>gfx</strong> @__gfx__ <em> Hi <a

    href="/foo">@foo</a> </em> _Hi @foo_
  32. w__foo__Λ<strong>foo</strong>ʹม׵͢Δॲཧ͸ SFEDBSQFU͕΍͍ͬͯΔ w@fooΛ<a href="/foo">@foo</a>ʹม׵͢Δॲཧ͸ɺ SFEDBSQFUΑΓޙ޻ఔͷ.FOUJPOϑΟϧλʔ͕΍͍ͬͯΔ wͭ·Γ.FOUJPOϑΟϧλʔͷೖྗͷ࣌఺Ͱɺ@__gfx__͸ @<strong>gfx</strong>ʹͳͬͯ͠·͍ͬͯΔ

  33. Redcarpet filter Mention filter @__gfx__ @<strong>gfx</strong> @<strong>gfx</strong> ͳΜ͔<strong>λά͍ͭͯΔ͠ ͜Ε͸ϝϯγϣϯ͡Όͳ͍ͳ ͳΜ͔ઌ಄ʹ@͍ͭͯΔ͚Ͳ

    ڧௐه๏ʹϚον͢Δ͔Βڧௐ͠ͱ͜
  34. w ࠜຊతʹ͜ͷ໰୊ʹରॲ͢Δʹ͸ɺSFEDBSQFUʹखΛՃ͑ͯϝϯγϣϯه๏ ͷ஌ࣝΛ༩͑ΔʢϝϯγϣϯͷҰ෦ͩͬͨΒڧௐ͠ͳ͍ʣඞཁ͕͋Δ w ͔͠͠SFEDBSQFUͷGPSL͸࠷ऴखஈͰ͋ΓɺͰ͖Ε͹΍Γͨ͘ͳ͍ w ϫʔΫΞϥ΢ϯυͱͯ͠ɺ.FOUJPOϑΟϧλʔʹ@<strong>gfx</ strong>͕౉͞ΕͨΒɺ@__gfx__ʹ໭ͯ͠ϝϯγϣϯͱͯ͠ѻ͑͹ྑ͍ʁ w ڧௐه๏͸_͚ͩͰͳ͘*΋࢖͑ΔͷͰ@<strong>gfx</strong>ͷݩ

    ͷ.BSLEPXOιʔε͕ɺ@**gfx**ͩͬͨՄೳੑ΋͋Δ
  35. None
  36. (JU)VC͸͜ͷ໰୊ʹ Ͳ͏ରॲ͍ͯ͠Δͷ͔

  37. None
  38. None
  39. .BSLEPXOͰϝϯγϣϯͰ͖ΔαʔϏεΛ࡞ΔͳΒɺ Ϣʔβʔ໊ʹ͸_Λ࢖͑ͳ͍Α͏ʹͨ͠ํ͕ྑ͍ গͳ͘ͱ΋ઌ಄ͱ຤ඌͷ_͸ආ͚͍ͨ

  40. ݹ͍Ωϟογϡ໰୊ ೥݄ 

  41. .BSLEPXOϨϯμϦϯάͷύϑΥʔϚϯε w 8FCαʔϏεͱͯ͠ɺϢʔβʔʹͱͬͯշదͳϨεϙϯελΠ ϜΛୡ੒͢Δͱ͍͏จ຺Ͱ͸ɺ.BSLEPXO RJJUBNBSLEPXO ͷ ϨϯμϦϯά͸ॏ͍ w ຊจͷ಺༰΍௕͞ʹΑͬͯॲཧ͕࣌ؒେ͖͘มΘΔ w

    ڊେͳςʔϒϧΛؚΜͩهࣄ͸ɺϨϯμϦϯάʹඵ͔͔ۙ͘ Δ͜ͱ΋͋Δ
  42. ϨϯμϦϯά݁ՌΛΩϟογϡ͢Δ w ౤ߘ࣌ʹҰ౓͚ͩϨϯμϦϯάͯ͠ɺ݁ՌΛΩϟογϡ ͓ͯ͘͠ w هࣄϖʔδӾཡϦΫΤετʹରͯ͠ຖճϨϯμϦϯά͸ ͠ͳ͍

  43. ݹ͍Ωϟογϡ໰୊ w RJJUBNBSLEPXO͸೔ʑਐԽ͍ͯ͠ΔͨΊɺ౤ߘ࣌ʹΩϟο γϡ͞ΕͨϨϯμϦϯά݁Ռͱɺ࠷৽ͷϨϯμϥʔͰϨϯ μϦϯάͨ͠৔߹ͷ݁Ռʹဃ཭͕ͰΔ w ࠣࡉͳมߋͰ͋Ε͹ݹ͍ΩϟογϡΛࢀর͠ଓ͚ͯ΋ྑ͍ ͕ɺ944ͳͲͷ੬ऑੑରԠͷ৔߹͸৽͍͠ϨϯμϥʔͰ֬ ࣮ʹϨϯμϦϯά͠௚͍ͨ͠

  44. ࠶ϨϯμϦϯάػߏ w *ODSFNFOUBMͳSFOEFSFSWFSTJPO *OUFHFS Λఆٛ͢Δ w ϨϯμϦϯά݁ՌͷΩϟογϡʹɺͦͷ࣌఺ͰͷSFOEFSFSWFSTJPOΛҰॹʹ֨ೲ͓ͯ͘͠ w هࣄΫϥεͷϨϯμϦϯά݁ՌΛฦ͢ϝιου಺ͰɺΩϟογϡͷSFOEFSFSWFSTJPO͕ݱ ࡏͷWFSTJPOΑΓ΋ݹ͍৔߹͸ࣗಈతʹ࠶ϨϯμϦϯάΛ࣮ߦ͢Δ

    w ࣮ࡍʹ͸શϦΫΤετͰ࠶ϨϯμϦϯά͕૸Δͱෛՙͷ໰୊͕͋ΔͷͰɺ֬཰తʹ࣮ ߦ͞ΕΔΑ͏ʹ͠ɺ࣌ؒͱڞʹ཰Λঃʑʹ্͍͛ͯ͘ w RJJUBNBSLEPXOʹखΛՃ͑ͨ৔߹΍ɺԿΒ͔ͷཧ༝Ͱશهࣄͷ࠶ϨϯμϦϯάΛ࣮ߦ͠ ͍ͨ৔߹͸SFOEFSFSWFSTJPOΛ ͢Δ
  45. class Article < ActiveRecord::Base CURRENT_RENDERER_VERSION = 3 def rendered_body if

    cached_body_renderer_version < CURRENT_RENDERER_VERSION self.cached_body = render(markdown_body) self.cached_body_renderer_version = CURRENT_RENDERER_VERSION end cached_body end end
  46. ೥݄ 

  47. None
  48. None
  49. None
  50. None
  51. .BSLEPXO͸௚઀)5.-λάΛೖྗͰ͖Δ ໌Β͔ʹةݥͳλά΍ଐੑ͸αχλΠζ͍͕ͯͨ͠ɺ DMBTTଐੑ͸ڐՄ͍ͯͨ͠ <span class="fa fa-spin"> ·ΘΔίϝϯτ </span>

  52. None
  53. ΑΓݫ֨ͳαχλΠζ w 2JJUBͷ6*ʹ࢖ΘΕ͍ͯΔDMBTTΛࢦఆ͢Δ͜ͱͰɺ2JJUBΛ໛฿ͨ͠ϑΟογϯάϖʔδΛ࡞ ੒Ͱ͖ͯ͠·͏ w FH2JJUBͷϩάΠϯϖʔδΛ໛฿ͨ͠ϑΥʔϜΛ࡞Γɺ֎෦αΠτ΁ύεϫʔυΛૹ৴͢Δ w ͜Ε·Ͱ΋αχλΠζ͸͍͕ͯͨ͠ɺϗϫΠτϦετϧʔϧΛΑΓݫ֨ʹ͠ɺར༻Ͱ͖Δ )5.-ཁૉ΍ଐੑΛݶఆతʹͨ͠ w

    HSFFONBU SFEDBSQFU ʹ͓͍ͯɺதؒϝλσʔλΛDMBTTଐੑͱͯ͠ग़ྗ͍ͯ͠ΔՕॴ͕͋ͬ ͨͷͰɺผͷEBUB ଐੑʹग़ྗ͢ΔΑ͏ʹมߋ͠ɺϢʔβʔʹΑΔೖྗͱ۠ผͰ͖ΔΑ͏ ʹͨ͠
  54. ͜Ε͔Β

  55. $PNNPO.BSL͸ʁ w ௕ظతʹ͸Ҡߦ͍ͨ͠ʢݸਓͷײ૝ʣ͕ɺطଘͷهࣄσʔ λͷҠߦ͕େมͦ͏ w (JU)VC͸$PNNPO.BSL΁ͷҠߦ࣌ɺ৽چͷϨϯμϥʔͰ ղऍ͕ҟͳΔυΩϡϝϯτ͸ม׵ॲஔΛߦͳͬͨ w IUUQTHJUIVCFOHJOFFSJOHDPNBGPSNBMTQFDGPS HJUIVCNBSLEPXO

  56. Thank you