Slide 1

Slide 1 text

PostCSS ͱ͸Կ͔ Yoshihide Jimbo @ Kaizen Platform, Inc. Grand-Frontend-Osaka 2015 Summer 2015/08/22

Slide 2

Slide 2 text

@jmblog Front-end engineer Remote worker Yoshihide Jimbo

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Agenda 1. PostCSS ͱ͸ 2.PostCSS Ͱग़དྷΔ͜ͱ 3.PostCSS ͷύϑΥʔϚϯε 4.PostCSS ͷ࢖͍ಓ 5.PostCSS ͷ͜Ε͔ΒΛ༧ଌ

Slide 5

Slide 5 text

1. PostCSS ͱ͸

Slide 6

Slide 6 text

τϨϯυ

Slide 7

Slide 7 text

770,000 downloads in the last month with npm grunt-cli: 890,000 downloads Less: 1,050,000 downloads gulp: 1,861,631 downloads

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

https:/ /twitter.com/mdo/status/591364406816079873

Slide 12

Slide 12 text

PostCSS ͱ͸

Slide 13

Slide 13 text

CSS PostCSS new CSS PostCSS ͱ͸ PostCSS is a tool for transforming CSS with JS plugins.

Slide 14

Slide 14 text

CSS new CSS Parser Stringifier var gulp = require('gulp'); var postcss = require('gulp-postcss'); gulp.task('css', function() { gulp.src('./src/**/*.css') .pipe(postcss([])) .pipe(gulp.dest('./dest')) }); PostCSS ͱ͸

Slide 15

Slide 15 text

Lj Plugin Parser Stringifier var gulp = require('gulp'); var postcss = require('gulp-postcss'); gulp.task('css', function() { var plugins = [ require('postcss-plugin1'), require("postcss-plugin2") ]; gulp.src('./src/**/*.css') .pipe(postcss(plugins)) .pipe(gulp.dest('./dest')) }); CSS new CSS Lj Plugin PostCSS ͱ͸

Slide 16

Slide 16 text

PostCSS ͱ͸ CSS Parser CSS Node Tree API Source Map Generator Node Tree Stringifier • PostCSS ຊମʹؚ·ΕΔͷ͸ɺ࣍ͷ 4 ͭͷػೳɻ CSS Λύʔεͯ͠ɺϊʔυπϦʔʢASTʣ ʹม׵ ϊʔυπϦʔΛૢ࡞͢Δ API Λఏڙ Source map Λੜ੒ ϊʔυπϦʔΛจࣈྻʹ࠶ม׵ • PostCSS ୯ମ͚ͩ͸ CSS ʹରͯ͠มߋ͸Ұ੾Ճ͑ͳ͍ɻ

Slide 17

Slide 17 text

• CSS ʹର͢Δ༷ʑͳมߋ͸ɺϓϥάΠϯ͕ߦ͏ɻ • ϓϥάΠϯͷ࢓૊Έγϯϓϧɻ୯ͳΔ JS ͷ function Ͱɺ֤ϓϥάΠϯ͸ ϊʔ υπϦʔΛड͚औΓɺಛఆͷϊʔυΛಡΈ͜ΜͩΓɺෆཁͳϊʔυΛऔΓআ͍ͨ Γɺ৽͍͠ϊʔυΛ௥Ճ͢Δɻͦͯ͠ɺมߋΛՃ͑ͨϊʔυπϦʔΛ return ͠ ͯɺ࣍ͷϓϥάΠϯʹड͚౉͢ɻ • ֤ϓϥάΠϯ͸୯ػೳͷΈ࣋ͭΑ͏ΨΠυϥΠϯͰਪ঑͞Ε͍ͯΔɻैͬͯɺҰ ͭҰͭͷϓϥάΠϯ͸খ͍͞΋ͷ͕ଟ͍ɻ • ΍Γ͍ͨ͜ͱʹԠͯ͡ɺ༷ʑͳϓϥάΠϯΛ૊Έ߹Θͤͯར༻͢Δ͜ͱʹͳΔɻ ϓϥάΠϯͱ͸

Slide 18

Slide 18 text

஫ҙ • ʮPostCSSʯͱ͍͏ݴ༿͸ɺπʔϧຊମΛࢦ͍ͯ͠Δ৔߹ͱɺϓϥάΠϯΛؚ ΊͨΤίγεςϜશମΛࢦ͍ͯ͠Δ৔߹ͱɺಛఆͷϓϥάΠϯ͚ͩΛࢦ͍ͯ͠Δ ৔߹͕͋ΔɻίϯςΩετʹؾΛ͚ͭΑ͏ɻ • Postprocessor ʢϙετϓϩηοαʔʣͱ͍͏ݴ༿͕ͨ·ʹग़ͯ͘Δ͕ɺ PostCSS ͕ग़དྷΔ͜ͱ͸ Postprocessing ʹݶఆ͞Εͳ͍ɻ࣮ଶͱ߹Θͣɺ PostCSS νʔϜ΋࢖͏ͷΛ΍ΊͨͷͰ๨ΕΑ͏ɻɹ (›°□°ʣ›ớ ᵲᴸᵲ

Slide 19

Slide 19 text

2. PostCSS Ͱग़དྷΔ͜ͱ

Slide 20

Slide 20 text

PostCSS Ͱग़དྷΔ͜ͱ • Future CSS SyntaxɹɹW3CͰ࢓༷ࡦఆதͷ࣍ੈ୅ CSS ͷઌऔΓ • Language ExtensionsɹɹSass ͷΑ͏ͳಠ֦ࣗு • FallbacksɹɹϑΥʔϧόοΫʢޙํޓ׵ʣ • Optimizationsɹɹ࠷దԽ • Analysisɹɹ෼ੳ • OthersɹɹͳͲͳͲ

Slide 21

Slide 21 text

Future CSS Syntax W3CͰ࢓༷ࡦఆதͷ࣍ੈ୅ CSS ͷઌऔΓ

Slide 22

Slide 22 text

ม਺ (CSS Variables) :root { --color: red; } div { color: var(--color); } div { color: red; } https:/ /github.com/postcss/postcss-custom-properties Lj IN OUT

Slide 23

Slide 23 text

ΧελϜηϨΫλʔ @custom-selector :--heading h1, h2, h3, h4, h5, h6; article :--heading + p { margin-top: 0; } article h1 + p, article h2 + p, article h3 + p, article h4 + p, article h5 + p, article h6 + p { margin-top: 0; } https:/ /github.com/postcss/postcss-custom-selectors Lj IN OUT

Slide 24

Slide 24 text

Color ؔ਺ body { background: color(red a(90%)) } body { background: rgba(255, 0, 0, 0.9) } https:/ /github.com/postcss/postcss-color-function Lj IN OUT

Slide 25

Slide 25 text

ϑΟϧλʔ .blur { filter: blur(4px); } .blur { filter: url('data:image/svg+xml;utf8,#filter'); filter: blur(4px); } https:/ /github.com/iamvdo/pleeease-filters Lj IN OUT

Slide 26

Slide 26 text

:matches ٖࣅΫϥε p:matches(:first-child, .special) { color: red; } p:first-child, p.special { color: red; } https:/ /github.com/postcss/postcss-selector-matches Lj IN OUT

Slide 27

Slide 27 text

cssnext Future CSS Syntax ܥϓϥάΠϯ܈Λ 1 ͭʹ·ͱΊͯ࢖͍΍ͨ͘͢͠ϓϥάΠϯύοΫɻ CSS ൛ͷ Babel Έ͍ͨͳ΋ͷɻ

Slide 28

Slide 28 text

cssnext Ͱ΋ŋŋŋ࢖͍͍ͨϓϥάΠϯ͸ cssnext ܦ༝Ͱ͸ͳ͘ݸผͰ࢖ͬͨ΄͏͕͍͍͔΋ʁ https:/ /github.com/postcss/postcss/issues/477

Slide 29

Slide 29 text

Language Extensions Sass ͷΑ͏ͳಠ֦ࣗு

Slide 30

Slide 30 text

@if จ .foo { @if 3 < 5 { background: green; } @else { background: blue; } } .foo { background: green; } https:/ /github.com/andyjansson/postcss-conditionals Lj IN OUT

Slide 31

Slide 31 text

Sass ͬΆ͍ม਺ $blue: #056ef0; $column: 120px; .menu_link { background: $blue; width: $column; } .menu_link { background: #056ef0; width: 200px; } https:/ /github.com/postcss/postcss-simple-vars Lj IN OUT

Slide 32

Slide 32 text

@for จ @for $i from 1 to 3 { .b-$i { width: $(i)px; } } .b-1 { width: 1px } .b-2 { width: 2px } .b-3 { width: 3px } https:/ /github.com/antyakushev/postcss-for Lj IN OUT

Slide 33

Slide 33 text

@mixin @define-mixin icon $network, $color: blue { .icon.is-$(network) { color: $color; @mixin-content; } } @mixin icon twitter { background: url(twt.png); } .icon.is-twitter { color: blue; background: url(twt.png); } https:/ /github.com/postcss/postcss-mixins Lj IN OUT

Slide 34

Slide 34 text

ωετ .phone { &_title { width: 500px; body.is_dark & { color: white; } } } .phone_title { width: 500px; } body.is_dark .phone_title { color: white; } https:/ /github.com/postcss/postcss-nested Lj IN OUT

Slide 35

Slide 35 text

PreCSS Sass ʹࣅͨߏจΛॻ͚ΔΑ͏ʹ͢ΔͨΊͷϓϥάΠϯύοΫ

Slide 36

Slide 36 text

Fallbacks ϑΥʔϧόοΫʢޙํޓ׵ʣ

Slide 37

Slide 37 text

Autoprefixer a { display: flex; } a { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex } https:/ /github.com/postcss/autoprefixer Lj IN OUT

Slide 38

Slide 38 text

opacity for IE8 .foo { opacity: .5; } .foo { opacity: .5; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; } https:/ /github.com/iamvdo/postcss-opacity Lj IN OUT

Slide 39

Slide 39 text

rgba() for IE8 body { background: rgba(153, 221, 153, 0.8); } body { background: #99DD99; background: rgba(153, 221, 153, 0.8); } https:/ /github.com/postcss/postcss-color-rgba-fallback Lj IN OUT

Slide 40

Slide 40 text

Optimization ࠷దԽ

Slide 41

Slide 41 text

Reduce calc() h1 { font-size: calc(16px * 2); height: calc(100px - 2em); } h1 { font-size: 32px; height: calc(100px - 2em) } https:/ /github.com/postcss/postcss-calc Lj IN OUT

Slide 42

Slide 42 text

Reduce @charset rule .foo { color: red; } @charset "Shift_JIS"; ... @charset "Shift_JIS"; ... @charset "Shift_JIS"; .foo { color: red; } ... https:/ /github.com/hail2u/postcss-single-charset Lj IN OUT

Slide 43

Slide 43 text

cssnano minifyɺoptimize ܥͷϓϥάΠϯ܈Λ 1 ͭʹͨ͠ϓϥάΠϯύοΫ

Slide 44

Slide 44 text

Others ͦͷଞ

Slide 45

Slide 45 text

ࣗಈ੔ܗ .class, #id { color : blue; border :solid #ddd 1px} .class, #id { color: blue; border: 1px solid #ddd; } https:/ /github.com/morishitter/cssfmt Lj IN OUT

Slide 46

Slide 46 text

stylelint Modern CSS linter

Slide 47

Slide 47 text

Fun ͓༡ͼ

Slide 48

Slide 48 text

British English ͰίʔυΛॻ͚ΔΑ͏ʹ body { background-colour: grey !please; transparency: 0.3; text-align: centre; text-transform: capitalise; } body { background-color: gray !important; opacity: 0.7; text-align: center; text-transform: capitalize; } https:/ /github.com/HashanP/postcss-spiffing Lj IN OUT

Slide 49

Slide 49 text

؆୯ͳϓϥάΠϯͷίʔυྫ

Slide 50

Slide 50 text

ྫʣOpacity fallbacks for IE8 var postcss = require('postcss'); module.exports = postcss.plugin('postcss-opacity', function () { return function (css) { css.eachDecl(function(decl) { if (decl.prop === 'opacity') { decl.parent.insertAfter(decl, { prop: '-ms-filter', value: '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + (parseFloat(decl.value) * 100) + ')"' }); } }); }; }); ؆୯ͳϓϥάΠϯͳΒ͜Ε͙Β͍ͷίʔυྔͰॻ͚ͯ͠·͏ɻ

Slide 51

Slide 51 text

PostCSS.parts PostCSS ͷϓϥάΠϯΛݕࡧͰ͖ΔαΠτ

Slide 52

Slide 52 text

github.com/postcss/postcss README ʹ΋ΧςΰϦʔ෼͚͞ΕͨϓϥάΠϯͷϦετ͕͋Δ

Slide 53

Slide 53 text

3. PostCSS ͷύϑΥʔϚϯε

Slide 54

Slide 54 text

Preprocessors

Slide 55

Slide 55 text

Preprocessors PostCSS* LibSass Less Stylus Ruby Sass 36ms 136ms (3.8x slower) 160ms (4.4x slower) 167ms (4.6x slower) 1084ms (30.1x slower) * postcss-nested + postcss-simple-vars + postcss-calc + postcss-mixins C++ Ͱॻ͔Εͨ LibSass ΑΓ΋ 4 ഒۙ͘଎͍

Slide 56

Slide 56 text

Vendor Prefixers

Slide 57

Slide 57 text

Vendor Prefixers Compass 59ms 2564ms (43.2x slower) * Autoprefixer Compass ΑΓ΋ 43 ഒҎ্଎͍ PostCSS*

Slide 58

Slide 58 text

͜͜·Ͱͷ·ͱΊ

Slide 59

Slide 59 text

͜͜·Ͱͷ·ͱΊ • PostCSS ͸ CSS ʹ͍Ζ͍ΖͳมߋΛՃ͑ΔͨΊͷπʔϧɻ • ༷ʑͳϓϥάΠϯ͕ଘࡏ͍ͯ͠Δɻ • ࣍ੈ୅ CSS ΛઌऔΓͯ͠ॻ͚ΔΑ͏ʹ΋ͳΔ͠ɺSass ͱಉ͡Α͏ͳίʔυΛॻ ͘͜ͱ΋Ͱ͖Δ͠ɺ࠷దԽ΍෼ੳɺࣗಈ੔ܗͳΜ͔΋Ͱ͖Δɻ • طଘͷπʔϧͱൺ΂ͯ΋ύϑΥʔϚϯεʹ༏Ε͍ͯΔɻ

Slide 60

Slide 60 text

4. PostCSS ͷ࢖͍ಓ

Slide 61

Slide 61 text

Sass ΍ Less ͷ୅ΘΓͱͯ͠࢖͏

Slide 62

Slide 62 text

• ύϑΥʔϚϯεʹ༏Ε͍ͯΔɻ • Sass Ͱ͸೉͍͠ಠࣗػೳ֦ு΋Մೳɻ • Sass ͱͷޓ׵ੑ͸ͳ͍ͷͰɺطଘͷ SCSS ϑΝΠϧ͕ͦͷ··࢖͑ΔΘ͚Ͱ ͸ͳ͍ɻ • ֦ு͗͢͠ΔͱɺΦϨΦϨ Preprocesser ʹͳͬͯ͠·͍ɺϝϯςφϯείε τ΋͔͔Δ͠ɺ৽نϝϯόʔͷֶशίετ΋͔͔Δɻ Sass ΍ Less ͷ୅ΘΓͱͯ͠࢖͏ ϝϦοτ σϝϦοτ PreCSS ͳͲΛར༻͢Δ

Slide 63

Slide 63 text

Compass ͷ୅ΘΓͱͯ͠࢖͏

Slide 64

Slide 64 text

• Ҡߦίετ͕͔͔Δɻ͚ͲɺͦΖͦΖͦͷίετΛ෷ͬͯ΋͍͍ࠒ߹͍͡Όͳ ͍͔ͱݸਓతʹ͸ࢥ͍·͢ɻ Compass ͷ୅ΘΓͱͯ͠࢖͏ ϝϦοτ σϝϦοτ • ύϑΥʔϚϯεʹ༏Ε͍ͯΔɻ40ഒҎ্ʂ • mixin Ͱ͸ͳ͘ૉͷ CSS Ͱίʔυ͕ॻ͚Δɻ • Compass ͸2015೥1݄Ҏ߱ɺ΄ͱΜͲ։ൃ͕ࢭ·ͬͯΔ༷ࢠɻͦΖͦΖΦϫίϯʁ Autoprefixer ΍ Fallback ܥϓϥάΠϯΛར༻͢Δ

Slide 65

Slide 65 text

࣍ੈ୅ CSS ΛઌऔΓ͢Δ

Slide 66

Slide 66 text

• Preprocessor ʹґଘͤͣ ૉͷ CSS ͱͯ͠ɺม਺ͳͲͷศརػೳ͕࢖͑Δɻ • ES2015(ES6) ͱҧͬͯɺ࢓༷ࡦఆ͸΄ͱΜͲ͕ Editor's Draft ͷஈ֊ɻ • ·ͩ·ͩ࢓༷͕มߋ͞ΕΔՄೳੑ͸͋Δɻ • ࢓༷͕มߋ͞ΕΔͱɺͦͷରԠ͕ඞཁʹͳͬͯ͘Δɻ͔͠΋ɺར༻͍ͯ͠Δϓϥ άΠϯ͕৽͍͠࢓༷ʹ͍ͭରԠ͢Δͷ͔ɺ͋Δ͍͸ݹ͍࢓༷΋ಉ࣌ʹαϙʔτ͠ ͯ͘ΕΔ͔Ͳ͏͔͸ɺ࡞ऀ࣍ୈɻ • ΋͏গ͠࢓༷͕҆ఆ͔ͯ͠Βಋೖͯ͠΋͍͍Μ͡Όͳ͍͔ͱݸਓతʹ͸ࢥ͏ɻ ࣍ੈ୅ CSS ΛઌऔΓ͢Δ ϝϦοτ σϝϦοτ nextcss ͳͲΛར༻͢Δ

Slide 67

Slide 67 text

ݱ࣮తͳ࢖͍ํ ຊ൪ͷϓϩμΫτͰಋೖ͢Δ৔߹

Slide 68

Slide 68 text

ݱ࣮తͳ࢖͍ํ • PostCSS ͸ Grunt, Gulp, webpack ͳͲओཁͳϏϧυπʔϧʹରԠ͍ͯ͠Δͷ ͰɺطଘͷϏϧυϑϩʔʹಋೖ͠΍͍͢ɻ • ·ͣ͸ Sass Λ࢖͍ͳ͕Β Autoprefixer, cssnano Λಋೖͯ͠ΈΔɻಛʹ Autoprefixer ͸࢖ͬͯଛ͸ͳ͍ɻͱ͍͏͔ɺඞਢΞΠςϜɻ .pipe( sass() ) .pipe( postcss([ require('autoprefixer'), require('cssnano') ]) )

Slide 69

Slide 69 text

ݱ࣮తͳ࢖͍ํ • ঃʑʹɺଞͷϓϥάΠϯ΋ࢼͯ͠ΈΔɻFallback ܥ ΍ Optimization ܥɺ CSSfmt ͳͲ͸ɺݩͷ Sass ϑΝΠϧΛॻ͖׵͑ΔҠߦίετ͕͔͔Βͳ͍ͷ Ͱɺಋೖ͠΍͍͢ɻ .pipe( sass() ) .pipe( postcss([ require('autoprefixer'), require('postcss-will-change'), require('postcss-selector-not'), require('postcss-selector-matches'), require('cssnano') ]) )

Slide 70

Slide 70 text

ݱ࣮తͳ࢖͍ํ • খ͞Ίͷ৽͍͠ϓϩδΣΫτͰ͸ɺ࣮ݧతʹ Sass Λ࢖Θͣ PostCSS ͚ͩͰॻ ͍ͯΈΔͷ΋Ұͭͷબ୒ࢶɻͦͷ৔߹ɺSass ͱಉ౳ͷػೳΛ͢΂ͯ࢖͓͏ͱͤ ͣɺඞཁ࠷௿ݶͷ΋ͷ͚ͩ࠾༻ͨ͠΄͏͕Α͍ɻ .pipe( postcss([ require('postcss-simple-vars'), require('autoprefixer'), require('postcss-will-change'), require('postcss-selector-not'), require('postcss-selector-matches'), require('cssnano') ]) )

Slide 71

Slide 71 text

ݱ࣮తͳ࢖͍ํ • ͨͩ͠ɺ͜ΕΒ͸͋͘·Ͱɺଉͷ௕͍ຊ൪ͷϓϩμΫτͰ࠾༻͢Δ৔߹ɻݸਓత ͳϓϩδΣΫτͰ͸ɺࡉ͔͍͜ͱ͸ؾʹͤͣʹɺศརͩͱࢥͬͨϓϥάΠϯ͸Ͳ ΜͲΜ࢖ͬͯɺΑ͔ͬͨ͜ͱ΋ѱ͔ͬͨ͜ͱ΋ίϛϡχςΟʹϑΟʔυόοΫ͠ ͍͖ͯ·͠ΐ͏ɻࣗ෼ͰϓϥάΠϯΛ࡞ͬͯެ։ͯ͠΋͍͍Ͱ͠ΐ͏ɻͦ͏΍ͬ ͯ Web ͷະདྷ͸࡞ΒΕ͍͖ͯ·͢ɻ

Slide 72

Slide 72 text

4. PostCSS ͷ͜Ε͔ΒΛ༧ଌ

Slide 73

Slide 73 text

• 2015೥ 8݄ 19೔ʹެ։ɻ • SCSS Parser ͕ਖ਼ࣜʹϦϦʔε͞Εͨɻ • ͜ΕʹΑΓɺCSS ϑΝΠϧ͚ͩͰͳ͘ɺSCSS ϑΝΠϧ΋ PostCSS Ͱॲཧ͢Δ ࣄ͕Ͱ͖ΔΑ͏ʹɻʢͨͩ͠ɺPostCSS Ͱ SCSS Λ CSS ʹίϯύΠϧͰ͖Δ Α͏ʹͳͬͨΘ͚Ͱ͸ͳ͍ɻʣ • ͜Ε·Ͱ͸ʮSass → CSS → PostCSS → new CSSʯ͔͠Ͱ͖ͳ͔͕ͬͨɺ
 ͜Ε͔Β͸ʮSass → PostCSS → new Sass → CSS → PostCSS → new CSSʯΈ͍ͨͳϑϩʔ΋Մೳʹɻ • SCSS Λ௚઀ Autoprefixer ʹ͔͚ͨΓɺcssfmt Ͱࣗಈ੔ܗͨ͠Γɺstylelint ͰίʔυνΣοΫͨ͠Γɻ όʔδϣϯ5.0

Slide 74

Slide 74 text

• Sass ͸ Bootstrap 4 ͕ Less ͔ΒҠߦͨ͜͠ͱͰ Preprocessor ͷதͰ͸ൈ͖ Μग़ͨײ͕͋Δɻ΋͏͠͹Β͘ Sass ͸ϝδϟʔͳଘࡏͰ͋Γଓ͚ͦ͏ɻ • PostCSS ͸ SCSS ϑΝΠϧΛ Parse Ͱ͖ΔΑ͏ʹͳͬͨ͜ͱͰɺSass ͱ͏· ͘ڞଘ͠ͳ͕ΒਐԽ͍ͯ͘͠ؾ഑ɻ • ͨͩ͠ɺPostCSS ͸ Preprocessor ͱͯ͠΋࢖͑Δ͠ɺଞͷ࢖͍ํ΋Ͱ͖Δͷ ͰɺՄೳੑ͸ Sass ͱൺ΂ͯඇৗʹେ͖͍ɻ • ͞Βʹɺγϯϓϧͳ࢓૊ΈͰɺ͏·͘ΤίγεςϜΛ࡞Γ্͍͛ͯΔͷͰɺਐԽ ͷεϐʔυ͕΋ͷ͘͢͝ૣ͍ɻ • ͱ͍͏Θ͚Ͱɺؾ͚ͮ͹ Sass Λۦஞͯ͠͠·ͬͯΔɺͱ͍͏͜ͱ΋͋Δ͔΋ Ͷɻ PostCSS vs Sass?

Slide 75

Slide 75 text

࠷ޙʹએ఻

Slide 76

Slide 76 text

Work with us! ҰॹʹੈքΛ KAIZEN ͢ΔϝϯόʔΛٻΊ͍ͯ·͢ʂ

Slide 77

Slide 77 text

Be a Growth Hacker! άϩʔεϋοΧʔͱͯ͠վળҊΛఏҊͯ͠ใुΛ֫ಘ͠·ͤΜ͔ʁ

Slide 78

Slide 78 text

Thanks!