[{"data":1,"prerenderedAt":7017},["ShallowReactive",2],{"category-ministack-2":3},{"count":4,"content":5},29,[6,356,884,2639,2858,3721,5389,5743,6306,6595],{"id":7,"title":8,"body":9,"category":341,"createdAt":343,"description":344,"extension":345,"index":346,"meta":347,"navigation":348,"path":349,"publish":348,"seo":350,"series":346,"seriesTitle":346,"stem":351,"tag":352,"thumbnail":346,"updatedAt":346,"__hash__":355},"articles\u002Farticles\u002Flaravel-plain-text-with-html.md","LaravelのMailableでHTMLメールとプレーンテキストメール両方を送信する方法",{"type":10,"value":11,"toc":331},"minimark",[12,16,21,24,32,37,40,49,53,60,70,80,83,87,90,182,192,202,205,208,214,229,250,269,272,279,327],[13,14,15],"p",{},"こんにちはjunです。Laravelでメール機能が伴う内容を実装していたときに、HTMLメールだけでなくプレーンテキストメールでも送付してほしいとの用件がありました。Laravelではメールを送信する時は大抵、Mailableを使用しますがその時に両方送る方法が意外と日本語でなかったので忘備録として記事を作りました。プレーンテキストとはなんぞや？というとこから解説するので、対策法をさっさと知りたい方は「Mailabeでのプレーンテキストの設定」を見てください。",[17,18,20],"h2",{"id":19},"プレーンテキストメールとhtmlメールの違い","プレーンテキストメールとHTMLメールの違い",[13,22,23],{},"HTMLメールは名の通り、HTMLの記法で作成されたメールです。生のデータにはHTMLが書かれており、メールクライアント側でHTMLをレンダリングしてメール内容を表示します。リッチなメールを送付できるというメリットがあります。デメリットとして環境やデバイスによってはメールが全く見れなくなることです。",[13,25,26,27,31],{},"HTMLメールが見れない環境や昔はプレーンテキストメールといった、メモ帳で書いた様な本当に純粋な文字だけのメールを利用します。メリットはどの端末でも必ず表示はできるので、確実に届けたいメールなどにはプレーンテキストがおすすめです。例えばGithubの二段階認証メールは",[28,29,30],"code",{},"Content-Type: text\u002Fplain; charset=UTF-8","とプレーンテキストで必ず送られ、毎週のお知らせメールはその両方が送られています。",[33,34,36],"h3",{"id":35},"どうやって確認できるの","どうやって確認できるの？",[13,38,39],{},"気になる方は届いたメールのソースを見てみましょう。Gmailであれば「画面右側の点々」をクリックして「メッセージのソースを表示」をクリックしますと、メールのヘッダやボディを確認できます。そのとき",[13,41,42,44,45,48],{},[28,43,30],{},"があれば、プレーンテキストメール形式で送付され、",[28,46,47],{},"Content-Type: text\u002Fhtml; charset=UTF-8","があればHTMLメールです。きちんとHTMLの記述があるのを確認してみてください。",[33,50,52],{"id":51},"なぜ両方ともつけることができるの","なぜ両方ともつけることができるの？",[13,54,55,56,59],{},"ちなみにメールにはHTMLとプレーン両方ともつけることは可能です。その場合環境に合わせてHTML・プレーンのものが表示されます。その仕組みはソースの中に ",[28,57,58],{},"Content-Type: multipart\u002Falternative; boundary=","のような記述をしようすることです。これはメールの内容を複数の形式で送りますよというヘッダ要素です。HTMLの内容とプレーンテキストの内容がソースでどこで分けているかを示しています。",[13,61,62,65,66,69],{},[28,63,64],{}," boundary=\"...\""," のboundaryの中身にある文字を境界として使用します。Laravelの場合はSwiftを使用しているので ",[28,67,68],{},"_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_","という文字（一部分はランダムです）が境界として使用され、",[71,72,77],"pre",{"className":73,"code":75,"language":76},[74],"language-text","Content-Type: multipart\u002Falternative; boundary=\"_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_\"\n\n--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_\nContent-Type: text\u002Fplain; charset=utf-8\nContent-Transfer-Encoding: quoted-printable\n\n（１）HTMLの記述’\n\n--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_\nContent-Type: text\u002Fhtml; charset=utf-8\nContent-Transfer-Encoding: quoted-printable\n\n（２）プレーンテキストの記述\n\n--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_\n","text",[28,78,75],{"__ignoreMap":79},"",[13,81,82],{},"上記の様な記述があると思います。ここで境界の文字を用いて２つの形式の内容を記述し、メールを送付してクライアントは適宜そのソースを汲み取って表示しています。",[17,84,86],{"id":85},"mailabeでのプレーンテキストの設定","Mailabeでのプレーンテキストの設定",[13,88,89],{},"前置きがながくなりましたが、LaravelのMailableでは以下の様に指定します。",[71,91,95],{"className":92,"code":93,"language":94,"meta":79,"style":79},"language-php shiki shiki-themes material-theme-ocean","\u002F**\n    * Build the message.\n    *\n    * @return $this\n*\u002F\npublic function build()\n{\n    return $this->view('mail.registration',[\n        'applay_user_name'=>$name,\n    ])->text('mail.registration_text',[ \u002F\u002F これ！\n        'applay_user_name'=>$name,\n    ])\n    ->subject('登録を受け付けました。');\n}\n","php",[28,96,97,105,111,117,123,129,135,141,147,153,159,164,170,176],{"__ignoreMap":79},[98,99,102],"span",{"class":100,"line":101},"line",1,[98,103,104],{},"\u002F**\n",[98,106,108],{"class":100,"line":107},2,[98,109,110],{},"    * Build the message.\n",[98,112,114],{"class":100,"line":113},3,[98,115,116],{},"    *\n",[98,118,120],{"class":100,"line":119},4,[98,121,122],{},"    * @return $this\n",[98,124,126],{"class":100,"line":125},5,[98,127,128],{},"*\u002F\n",[98,130,132],{"class":100,"line":131},6,[98,133,134],{},"public function build()\n",[98,136,138],{"class":100,"line":137},7,[98,139,140],{},"{\n",[98,142,144],{"class":100,"line":143},8,[98,145,146],{},"    return $this->view('mail.registration',[\n",[98,148,150],{"class":100,"line":149},9,[98,151,152],{},"        'applay_user_name'=>$name,\n",[98,154,156],{"class":100,"line":155},10,[98,157,158],{},"    ])->text('mail.registration_text',[ \u002F\u002F これ！\n",[98,160,162],{"class":100,"line":161},11,[98,163,152],{},[98,165,167],{"class":100,"line":166},12,[98,168,169],{},"    ])\n",[98,171,173],{"class":100,"line":172},13,[98,174,175],{},"    ->subject('登録を受け付けました。');\n",[98,177,179],{"class":100,"line":178},14,[98,180,181],{},"}\n",[13,183,184,187,188,191],{},[28,185,186],{},"text()","メソッドを使用することで前述の解説の様にプレーンテキスト用のmultipartを入れ込んでくれます。なお、引数は",[28,189,190],{},"view()","メソッドと同じでテンプレートファイルとデータを渡すことができます。この記法はLaravel5.3から利用できます。",[13,193,194,195],{},"参考\n",[196,197,201],"a",{"href":198,"rel":199},"https:\u002F\u002Flaravel.com\u002Fdocs\u002F9.x\u002Fmail#plain-text-emails",[200],"nofollow","Laravel9 Mail",[33,203,204],{"id":204},"テンプレートの記述とファイル構成のすすめ",[13,206,207],{},"私の場合は以下の様な構成とファイル名でメールテンプレートを管理しています。",[71,209,212],{"className":210,"code":211,"language":76},[74],"views\n│\n├── mail\n    ├── master.blade.php\n    ├── master_text.blade.php\n    ├── register.blade.php\n    └── register_text.blade.php\n",[28,213,211],{"__ignoreMap":79},[13,215,216,217,220,221,224,225,228],{},"まずviewsでmail用のテンプレートを格納するディレクトリ を作成し、そしてHプレーンテキスト用のテンプレートはTML用のものに",[28,218,219],{},"_text","をつけておきます。そして",[28,222,223],{},"master.blade.php","はレイアウトやHTMLのスタイルを定義しています。同じようにプレーン用のレイアウトファイルの",[28,226,227],{},"master_text.blade.php","を用意しておくといいです。",[71,230,233],{"className":92,"code":231,"filename":232,"language":94,"meta":79,"style":79},"{{$name}}様\n\u003Cp>いつもご利用いただきありがとうございます。\u003C\u002Fp>\n...\n","register.blade.php",[28,234,235,240,245],{"__ignoreMap":79},[98,236,237],{"class":100,"line":101},[98,238,239],{},"{{$name}}様\n",[98,241,242],{"class":100,"line":107},[98,243,244],{},"\u003Cp>いつもご利用いただきありがとうございます。\u003C\u002Fp>\n",[98,246,247],{"class":100,"line":113},[98,248,249],{},"...\n",[71,251,254],{"className":92,"code":252,"filename":253,"language":94,"meta":79,"style":79},"{{$name}}様\nいつもご利用いただきありがとうございます。\n...\n","register_text.blade.php",[28,255,256,260,265],{"__ignoreMap":79},[98,257,258],{"class":100,"line":101},[98,259,239],{},[98,261,262],{"class":100,"line":107},[98,263,264],{},"いつもご利用いただきありがとうございます。\n",[98,266,267],{"class":100,"line":113},[98,268,249],{},[17,270,271],{"id":271},"notifiableの場合",[13,273,274,275,278],{},"これはLaravel8しか確認していませんが、Notifiableで使用されるMailMessageの場合はプレーンテキストが自動的に作成されていました。以下の様に",[28,276,277],{},"toMail()","を作成しておけばHTMLもプレーンも送付されていました。",[71,280,282],{"className":92,"code":281,"language":94,"meta":79,"style":79},"public function toMail($notifiable)\n{\n    return (new MailMessage)\n                ->subject('メールアドレスが変更されました')\n                ->line(\"いつもご利用いただきありがとうございます。\")\n                ->line('連絡用メールアドレスの変更を受け付けました。')\n                ->line('※本メールは送信専用です。ご返信いただいても対応できませんのでご了承ください。')\n                ->line('※本メールにお心当たりがない場合は、恐れ入りますが破棄していただきますようお願いいたします。');\n}\n",[28,283,284,289,293,298,303,308,313,318,323],{"__ignoreMap":79},[98,285,286],{"class":100,"line":101},[98,287,288],{},"public function toMail($notifiable)\n",[98,290,291],{"class":100,"line":107},[98,292,140],{},[98,294,295],{"class":100,"line":113},[98,296,297],{},"    return (new MailMessage)\n",[98,299,300],{"class":100,"line":119},[98,301,302],{},"                ->subject('メールアドレスが変更されました')\n",[98,304,305],{"class":100,"line":125},[98,306,307],{},"                ->line(\"いつもご利用いただきありがとうございます。\")\n",[98,309,310],{"class":100,"line":131},[98,311,312],{},"                ->line('連絡用メールアドレスの変更を受け付けました。')\n",[98,314,315],{"class":100,"line":137},[98,316,317],{},"                ->line('※本メールは送信専用です。ご返信いただいても対応できませんのでご了承ください。')\n",[98,319,320],{"class":100,"line":143},[98,321,322],{},"                ->line('※本メールにお心当たりがない場合は、恐れ入りますが破棄していただきますようお願いいたします。');\n",[98,324,325],{"class":100,"line":149},[98,326,181],{},[328,329,330],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":79,"searchDepth":113,"depth":113,"links":332},[333,337,340],{"id":19,"depth":107,"text":20,"children":334},[335,336],{"id":35,"depth":113,"text":36},{"id":51,"depth":113,"text":52},{"id":85,"depth":107,"text":86,"children":338},[339],{"id":204,"depth":113,"text":204},{"id":271,"depth":107,"text":271},[342],"ministack","2022-03-07","LaravelのMilableでHTMLメールとプレーンテキストメール両方を送信する方法","md",null,{},true,"\u002Farticles\u002Flaravel-plain-text-with-html",{"title":8,"description":344},"articles\u002Flaravel-plain-text-with-html",[353,94,354],"laravel","network","Ru_0w8TnRhwaXPjcr0gSRvxAArbPnEm7l-VCgPS-v6w",{"id":357,"title":358,"body":359,"category":875,"createdAt":876,"description":877,"extension":345,"index":346,"meta":878,"navigation":348,"path":879,"publish":348,"seo":880,"series":346,"seriesTitle":346,"stem":881,"tag":882,"thumbnail":346,"updatedAt":346,"__hash__":883},"articles\u002Farticles\u002Fphpspredsheet-rich-text.md","Phpspreadsheetで書式があるとgetValue()で文字を取得できない",{"type":10,"value":360,"toc":873},[361,370,419,433,436,795,803,816,822,835,868,871],[13,362,363,364,369],{},"こんにちはjunです。PHPでエクセルをアップロードして、データを取得するという機能を実装する際に",[196,365,368],{"href":366,"rel":367},"https:\u002F\u002Fphpspreadsheet.readthedocs.io\u002Fen\u002Flatest\u002F",[200],"Phpspreadsheet","を使用することが多いと思います。アップロードされたエクセルを以下の様にしてセルの値を取得することができます。",[71,371,373],{"className":92,"code":372,"language":94,"meta":79,"style":79},"use \\PhpOffice\\PhpSpreadsheet\\IOFactory;\nuse \\PhpOffice\\PhpSpreadsheet\\Shared\\Date;\n\n\u002F\u002F $fileはエクセルファイル\n$spreadsheet = IOFactory::load($file);\n$worksheet = $spreadsheet->getSheetByName('Sheet1');\n\n\u002F\u002F A1のセルのデータを取得する\n$workSheet->getCell(\"A1\")->getValue();\n",[28,374,375,380,385,390,395,400,405,409,414],{"__ignoreMap":79},[98,376,377],{"class":100,"line":101},[98,378,379],{},"use \\PhpOffice\\PhpSpreadsheet\\IOFactory;\n",[98,381,382],{"class":100,"line":107},[98,383,384],{},"use \\PhpOffice\\PhpSpreadsheet\\Shared\\Date;\n",[98,386,387],{"class":100,"line":113},[98,388,389],{"emptyLinePlaceholder":348},"\n",[98,391,392],{"class":100,"line":119},[98,393,394],{},"\u002F\u002F $fileはエクセルファイル\n",[98,396,397],{"class":100,"line":125},[98,398,399],{},"$spreadsheet = IOFactory::load($file);\n",[98,401,402],{"class":100,"line":131},[98,403,404],{},"$worksheet = $spreadsheet->getSheetByName('Sheet1');\n",[98,406,407],{"class":100,"line":137},[98,408,389],{"emptyLinePlaceholder":348},[98,410,411],{"class":100,"line":143},[98,412,413],{},"\u002F\u002F A1のセルのデータを取得する\n",[98,415,416],{"class":100,"line":149},[98,417,418],{},"$workSheet->getCell(\"A1\")->getValue();\n",[13,420,421,424,425,428,429,432],{},[28,422,423],{},"getCell()","の引数を指定して再帰的に全ての列の値を取得して配列にするみたいなこともできるので、エクセルを用いてwebアプリへのデータ入力ができます。最初は",[28,426,427],{},"getValue()","を用いて問題なくセルの文字を取得できていました。しかしある日、お客さんから「このエクセルを読み取らせると変な文字が表示されます」という問い合わせをいただきました。サーバーにアップしたエクセルの内容を上記の様に取得してブラウザに表示するということをやっていたのですが、確かに",[28,430,431],{},"{}","という謎の文字がありました。",[13,434,435],{},"デバッグログを見てみると下記の様に一部の値がインスタンスとなっていました。",[71,437,439],{"className":92,"code":438,"language":94,"meta":79,"style":79},"array(\n'name' => \n  PhpOffice\\PhpSpreadsheet\\RichText\\RichText::__set_state(array(\n     'richTextElements' => \n    array (\n      0 => \n      PhpOffice\\PhpSpreadsheet\\RichText\\TextElement::__set_state(array(\n         'text' => 'テスト',\n      )),\n      1 => \n      PhpOffice\\PhpSpreadsheet\\RichText\\Run::__set_state(array(\n         'font' => \n        PhpOffice\\PhpSpreadsheet\\Style\\Font::__set_state(array(\n           'name' => '游ゴシック',\n           'size' => 12.0,\n           'bold' => false,\n           'italic' => false,\n           'superscript' => false,\n           'subscript' => false,\n           'underline' => 'none',\n           'strikethrough' => false,\n           'color' => \n          PhpOffice\\PhpSpreadsheet\\Style\\Color::__set_state(array(\n             'argb' => 'FF000000',\n             'hasChanged' => false,\n             'isSupervisor' => false,\n             'parent' => NULL,\n             'parentPropertyName' => NULL,\n          )),\n           'colorIndex' => NULL,\n           'isSupervisor' => false,\n           'parent' => NULL,\n           'parentPropertyName' => NULL,\n        )),\n         'text' => 'テス',\n      )),\n      2 => \n      PhpOffice\\PhpSpreadsheet\\RichText\\Run::__set_state(array(\n         'font' => \n        PhpOffice\\PhpSpreadsheet\\Style\\Font::__set_state(array(\n           'name' => '游ゴシック',\n           'size' => 12.0,\n           'bold' => false,\n           'italic' => false,\n           'superscript' => false,\n           'subscript' => false,\n           'underline' => 'none',\n           'strikethrough' => false,\n           'color' => \n          PhpOffice\\PhpSpreadsheet\\Style\\Color::__set_state(array(\n             'argb' => 'FF000000',\n             'hasChanged' => false,\n             'isSupervisor' => false,\n             'parent' => NULL,\n             'parentPropertyName' => NULL,\n          )),\n           'colorIndex' => NULL,\n           'isSupervisor' => false,\n           'parent' => NULL,\n           'parentPropertyName' => NULL,\n        )),\n         'text' => 'テスト',\n      )),\n    ),\n  )),\n)\n",[28,440,441,446,451,456,461,466,471,476,481,486,491,496,501,506,511,517,523,529,535,541,547,553,559,565,571,577,583,589,595,600,606,612,618,624,630,636,641,647,652,657,662,667,672,677,682,687,692,697,702,707,712,717,722,727,732,737,742,747,752,757,762,767,772,777,783,789],{"__ignoreMap":79},[98,442,443],{"class":100,"line":101},[98,444,445],{},"array(\n",[98,447,448],{"class":100,"line":107},[98,449,450],{},"'name' => \n",[98,452,453],{"class":100,"line":113},[98,454,455],{},"  PhpOffice\\PhpSpreadsheet\\RichText\\RichText::__set_state(array(\n",[98,457,458],{"class":100,"line":119},[98,459,460],{},"     'richTextElements' => \n",[98,462,463],{"class":100,"line":125},[98,464,465],{},"    array (\n",[98,467,468],{"class":100,"line":131},[98,469,470],{},"      0 => \n",[98,472,473],{"class":100,"line":137},[98,474,475],{},"      PhpOffice\\PhpSpreadsheet\\RichText\\TextElement::__set_state(array(\n",[98,477,478],{"class":100,"line":143},[98,479,480],{},"         'text' => 'テスト',\n",[98,482,483],{"class":100,"line":149},[98,484,485],{},"      )),\n",[98,487,488],{"class":100,"line":155},[98,489,490],{},"      1 => \n",[98,492,493],{"class":100,"line":161},[98,494,495],{},"      PhpOffice\\PhpSpreadsheet\\RichText\\Run::__set_state(array(\n",[98,497,498],{"class":100,"line":166},[98,499,500],{},"         'font' => \n",[98,502,503],{"class":100,"line":172},[98,504,505],{},"        PhpOffice\\PhpSpreadsheet\\Style\\Font::__set_state(array(\n",[98,507,508],{"class":100,"line":178},[98,509,510],{},"           'name' => '游ゴシック',\n",[98,512,514],{"class":100,"line":513},15,[98,515,516],{},"           'size' => 12.0,\n",[98,518,520],{"class":100,"line":519},16,[98,521,522],{},"           'bold' => false,\n",[98,524,526],{"class":100,"line":525},17,[98,527,528],{},"           'italic' => false,\n",[98,530,532],{"class":100,"line":531},18,[98,533,534],{},"           'superscript' => false,\n",[98,536,538],{"class":100,"line":537},19,[98,539,540],{},"           'subscript' => false,\n",[98,542,544],{"class":100,"line":543},20,[98,545,546],{},"           'underline' => 'none',\n",[98,548,550],{"class":100,"line":549},21,[98,551,552],{},"           'strikethrough' => false,\n",[98,554,556],{"class":100,"line":555},22,[98,557,558],{},"           'color' => \n",[98,560,562],{"class":100,"line":561},23,[98,563,564],{},"          PhpOffice\\PhpSpreadsheet\\Style\\Color::__set_state(array(\n",[98,566,568],{"class":100,"line":567},24,[98,569,570],{},"             'argb' => 'FF000000',\n",[98,572,574],{"class":100,"line":573},25,[98,575,576],{},"             'hasChanged' => false,\n",[98,578,580],{"class":100,"line":579},26,[98,581,582],{},"             'isSupervisor' => false,\n",[98,584,586],{"class":100,"line":585},27,[98,587,588],{},"             'parent' => NULL,\n",[98,590,592],{"class":100,"line":591},28,[98,593,594],{},"             'parentPropertyName' => NULL,\n",[98,596,597],{"class":100,"line":4},[98,598,599],{},"          )),\n",[98,601,603],{"class":100,"line":602},30,[98,604,605],{},"           'colorIndex' => NULL,\n",[98,607,609],{"class":100,"line":608},31,[98,610,611],{},"           'isSupervisor' => false,\n",[98,613,615],{"class":100,"line":614},32,[98,616,617],{},"           'parent' => NULL,\n",[98,619,621],{"class":100,"line":620},33,[98,622,623],{},"           'parentPropertyName' => NULL,\n",[98,625,627],{"class":100,"line":626},34,[98,628,629],{},"        )),\n",[98,631,633],{"class":100,"line":632},35,[98,634,635],{},"         'text' => 'テス',\n",[98,637,639],{"class":100,"line":638},36,[98,640,485],{},[98,642,644],{"class":100,"line":643},37,[98,645,646],{},"      2 => \n",[98,648,650],{"class":100,"line":649},38,[98,651,495],{},[98,653,655],{"class":100,"line":654},39,[98,656,500],{},[98,658,660],{"class":100,"line":659},40,[98,661,505],{},[98,663,665],{"class":100,"line":664},41,[98,666,510],{},[98,668,670],{"class":100,"line":669},42,[98,671,516],{},[98,673,675],{"class":100,"line":674},43,[98,676,522],{},[98,678,680],{"class":100,"line":679},44,[98,681,528],{},[98,683,685],{"class":100,"line":684},45,[98,686,534],{},[98,688,690],{"class":100,"line":689},46,[98,691,540],{},[98,693,695],{"class":100,"line":694},47,[98,696,546],{},[98,698,700],{"class":100,"line":699},48,[98,701,552],{},[98,703,705],{"class":100,"line":704},49,[98,706,558],{},[98,708,710],{"class":100,"line":709},50,[98,711,564],{},[98,713,715],{"class":100,"line":714},51,[98,716,570],{},[98,718,720],{"class":100,"line":719},52,[98,721,576],{},[98,723,725],{"class":100,"line":724},53,[98,726,582],{},[98,728,730],{"class":100,"line":729},54,[98,731,588],{},[98,733,735],{"class":100,"line":734},55,[98,736,594],{},[98,738,740],{"class":100,"line":739},56,[98,741,599],{},[98,743,745],{"class":100,"line":744},57,[98,746,605],{},[98,748,750],{"class":100,"line":749},58,[98,751,611],{},[98,753,755],{"class":100,"line":754},59,[98,756,617],{},[98,758,760],{"class":100,"line":759},60,[98,761,623],{},[98,763,765],{"class":100,"line":764},61,[98,766,629],{},[98,768,770],{"class":100,"line":769},62,[98,771,480],{},[98,773,775],{"class":100,"line":774},63,[98,776,485],{},[98,778,780],{"class":100,"line":779},64,[98,781,782],{},"    ),\n",[98,784,786],{"class":100,"line":785},65,[98,787,788],{},"  )),\n",[98,790,792],{"class":100,"line":791},66,[98,793,794],{},")\n",[13,796,797,798],{},"対象のエクセルのセルを見てみると文字が赤色になっていたりと装飾が当てられていました。原因がわかったので対処を行います。調査の結果似た様なissueがありました。",[196,799,802],{"href":800,"rel":801},"https:\u002F\u002Fgithub.com\u002FPHPOffice\u002FPhpSpreadsheet\u002Fissues\u002F442",[200],"RichText can not get the correct value, when one part is plain text and the other part is rich text.",[13,804,805,806,808,809,812,813,815],{},"方法としては",[28,807,427],{},"に加えて",[28,810,811],{},"getPlainText()","というメソッドを通すことで装飾されたセルの値（リッチテキスト）を取得することができます。しかし",[28,814,811],{},"には問題があり、なんとリッチテキストでない値に適用すると以下の様エラーが発生します。",[71,817,820],{"className":818,"code":819,"language":76},[74],"Call to a member function getPlainText() on string.\n",[28,821,819],{"__ignoreMap":79},[13,823,824,825,827,828,830,831,834],{},"つまり、",[28,826,427],{},"した時の値がリッチテキストインスタンスであるかをチェックして",[28,829,811],{},"を適用するかを分岐させる必要があります。リッチテキストは",[28,832,833],{},"\\PhpOffice\\PhpSpreadsheet\\RichText\\RichText","というクラスなので以下の様な関数を作成すれば問題ありません。",[71,836,838],{"className":92,"code":837,"language":94,"meta":79,"style":79},"use \\PhpOffice\\PhpSpreadsheet\\RichText\\RichText;\n\nfunction getCellValue($workSheet,$cell){\n    $val = $workSheet->getCell($cell)->getValue();\n    return ($val instanceof RichText)?$val->getPlainText():$val;\n}\n",[28,839,840,845,849,854,859,864],{"__ignoreMap":79},[98,841,842],{"class":100,"line":101},[98,843,844],{},"use \\PhpOffice\\PhpSpreadsheet\\RichText\\RichText;\n",[98,846,847],{"class":100,"line":107},[98,848,389],{"emptyLinePlaceholder":348},[98,850,851],{"class":100,"line":113},[98,852,853],{},"function getCellValue($workSheet,$cell){\n",[98,855,856],{"class":100,"line":119},[98,857,858],{},"    $val = $workSheet->getCell($cell)->getValue();\n",[98,860,861],{"class":100,"line":125},[98,862,863],{},"    return ($val instanceof RichText)?$val->getPlainText():$val;\n",[98,865,866],{"class":100,"line":131},[98,867,181],{},[13,869,870],{},"リッチテキストのインスタンスかをチェックして値を取得することでリッチテキストもプレーンテキストも対応することができました。こう考えるとやっぱりエクセルインポートなんてやめてCSVインポートにしておけばよかったなーと思っています。",[328,872,330],{},{"title":79,"searchDepth":113,"depth":113,"links":874},[],[342],"2022-02-28","書式を当てたセルから文字・値を取得する方法",{},"\u002Farticles\u002Fphpspredsheet-rich-text",{"title":358,"description":877},"articles\u002Fphpspredsheet-rich-text",[94],"vZGoVH1w7p4Zs6BmYkw-9jf7nQBYtDotePnJnccXEz4",{"id":885,"title":886,"body":887,"category":2628,"createdAt":2629,"description":2630,"extension":345,"index":346,"meta":2631,"navigation":348,"path":2632,"publish":348,"seo":2633,"series":346,"seriesTitle":346,"stem":2634,"tag":2635,"thumbnail":346,"updatedAt":346,"__hash__":2638},"articles\u002Farticles\u002Fjs-deep-copy.md","jsで配列内のオブジェクトの値が連動してしまう原因と対処法",{"type":10,"value":888,"toc":2616},[889,896,1057,1070,1073,1081,1189,1196,1201,1204,1209,1212,1216,1223,1236,1238,1246,1249,1449,1472,1530,1533,1535,1538,1541,1550,1554,1565,1734,1737,1741,1752,1935,1942,2151,2154,2158,2168,2175,2365,2368,2372,2375,2430,2433,2610,2613],[13,890,891,892,895],{},"こんにちはjunです。vue.jsとかでアプリを作るととき、一覧ページや複数個のデータを出力する時はオブジェクトが内包された配列データを使用することが多いと思います。例としては以下のような「記事一覧」用の",[28,893,894],{},"posts","データです。",[71,897,901],{"className":898,"code":899,"language":900,"meta":79,"style":79},"language-javascript shiki shiki-themes material-theme-ocean","const posts = [\n    {id:1,title:\"記事タイトル１\",content:\"...\"},\n    {id:2,title:\"記事タイトル２\",content:\"...\"},\n    {id:3,title:\"記事タイトル３\",content:\"...\"},\n    \u002F\u002F ...\n]\n","javascript",[28,902,903,920,970,1008,1046,1052],{"__ignoreMap":79},[98,904,905,909,913,917],{"class":100,"line":101},[98,906,908],{"class":907},"sJ14y","const",[98,910,912],{"class":911},"s0W1g"," posts ",[98,914,916],{"class":915},"sAklC","=",[98,918,919],{"class":911}," [\n",[98,921,922,925,929,932,936,939,942,944,947,951,953,955,958,960,962,965,967],{"class":100,"line":107},[98,923,924],{"class":915},"    {",[98,926,928],{"class":927},"s-wAU","id",[98,930,931],{"class":915},":",[98,933,935],{"class":934},"sx098","1",[98,937,938],{"class":915},",",[98,940,941],{"class":927},"title",[98,943,931],{"class":915},[98,945,946],{"class":915},"\"",[98,948,950],{"class":949},"sfyAc","記事タイトル１",[98,952,946],{"class":915},[98,954,938],{"class":915},[98,956,957],{"class":927},"content",[98,959,931],{"class":915},[98,961,946],{"class":915},[98,963,964],{"class":949},"...",[98,966,946],{"class":915},[98,968,969],{"class":915},"},\n",[98,971,972,974,976,978,981,983,985,987,989,992,994,996,998,1000,1002,1004,1006],{"class":100,"line":113},[98,973,924],{"class":915},[98,975,928],{"class":927},[98,977,931],{"class":915},[98,979,980],{"class":934},"2",[98,982,938],{"class":915},[98,984,941],{"class":927},[98,986,931],{"class":915},[98,988,946],{"class":915},[98,990,991],{"class":949},"記事タイトル２",[98,993,946],{"class":915},[98,995,938],{"class":915},[98,997,957],{"class":927},[98,999,931],{"class":915},[98,1001,946],{"class":915},[98,1003,964],{"class":949},[98,1005,946],{"class":915},[98,1007,969],{"class":915},[98,1009,1010,1012,1014,1016,1019,1021,1023,1025,1027,1030,1032,1034,1036,1038,1040,1042,1044],{"class":100,"line":119},[98,1011,924],{"class":915},[98,1013,928],{"class":927},[98,1015,931],{"class":915},[98,1017,1018],{"class":934},"3",[98,1020,938],{"class":915},[98,1022,941],{"class":927},[98,1024,931],{"class":915},[98,1026,946],{"class":915},[98,1028,1029],{"class":949},"記事タイトル３",[98,1031,946],{"class":915},[98,1033,938],{"class":915},[98,1035,957],{"class":927},[98,1037,931],{"class":915},[98,1039,946],{"class":915},[98,1041,964],{"class":949},[98,1043,946],{"class":915},[98,1045,969],{"class":915},[98,1047,1048],{"class":100,"line":125},[98,1049,1051],{"class":1050},"sC9rS","    \u002F\u002F ...\n",[98,1053,1054],{"class":100,"line":131},[98,1055,1056],{"class":911},"]\n",[13,1058,1059,1060,1064,1065,1069],{},"今回の記事で解説する内容は上記のような配列を別の変数に格納した時、スプレッド構文を使用して配列を生成したにもかかわらず、オブジェクト内の値が連動してしまったときの対処と原因について解説します。「どんなデータの状況だったか」という実装背景から話すので、ささっと原因からは知りたい人は「",[196,1061,1063],{"href":1062},"#%E5%8E%9F%E5%9B%A0","原因","」へ、解決方法だけ知りたい人は「",[196,1066,1068],{"href":1067},"#%E5%AF%BE%E5%87%A6%E6%B3%95","対処法","」へ移動してください。",[17,1071,1072],{"id":1072},"実装背景",[13,1074,1075,1076,1080],{},"vue.jsで編集画面を実装していた時です。編集画面は「入力された新しい値」と「登録済みの値（DBにある値）」を持たせておき、一部でその差分を確認できるようにするという",[1077,1078,1079],"del",{},"面倒な","実装がありました。内容としては「1日の予定表」みたいなもので、以下のようなデータ構造です。",[71,1082,1084],{"className":898,"code":1083,"language":900,"meta":79,"style":79},"const DATA_FROM_DB = response.data;\n\nconsole.log(DATA_FROM_DB);\n\u002F**\n{\n    date:\"2021-11-01\", \n    memo:\"...\",\n    todo:   \u002F\u002F この日の予定を入れる。\n    [\n        {id:1,content:\"AAAA\"},\n        {id:2,content:\"BBBB\"},\n        {id:3,content:\"CCCC\"},\n        ...\n    ]\n}\n**\u002F\n\n",[28,1085,1086,1107,1111,1127,1131,1135,1140,1145,1150,1155,1160,1165,1170,1175,1180,1184],{"__ignoreMap":79},[98,1087,1088,1090,1093,1095,1098,1101,1104],{"class":100,"line":101},[98,1089,908],{"class":907},[98,1091,1092],{"class":911}," DATA_FROM_DB ",[98,1094,916],{"class":915},[98,1096,1097],{"class":911}," response",[98,1099,1100],{"class":915},".",[98,1102,1103],{"class":911},"data",[98,1105,1106],{"class":915},";\n",[98,1108,1109],{"class":100,"line":107},[98,1110,389],{"emptyLinePlaceholder":348},[98,1112,1113,1116,1118,1122,1125],{"class":100,"line":113},[98,1114,1115],{"class":911},"console",[98,1117,1100],{"class":915},[98,1119,1121],{"class":1120},"sdLwU","log",[98,1123,1124],{"class":911},"(DATA_FROM_DB)",[98,1126,1106],{"class":915},[98,1128,1129],{"class":100,"line":119},[98,1130,104],{"class":1050},[98,1132,1133],{"class":100,"line":125},[98,1134,140],{"class":1050},[98,1136,1137],{"class":100,"line":131},[98,1138,1139],{"class":1050},"    date:\"2021-11-01\", \n",[98,1141,1142],{"class":100,"line":137},[98,1143,1144],{"class":1050},"    memo:\"...\",\n",[98,1146,1147],{"class":100,"line":143},[98,1148,1149],{"class":1050},"    todo:   \u002F\u002F この日の予定を入れる。\n",[98,1151,1152],{"class":100,"line":149},[98,1153,1154],{"class":1050},"    [\n",[98,1156,1157],{"class":100,"line":155},[98,1158,1159],{"class":1050},"        {id:1,content:\"AAAA\"},\n",[98,1161,1162],{"class":100,"line":161},[98,1163,1164],{"class":1050},"        {id:2,content:\"BBBB\"},\n",[98,1166,1167],{"class":100,"line":166},[98,1168,1169],{"class":1050},"        {id:3,content:\"CCCC\"},\n",[98,1171,1172],{"class":100,"line":172},[98,1173,1174],{"class":1050},"        ...\n",[98,1176,1177],{"class":100,"line":178},[98,1178,1179],{"class":1050},"    ]\n",[98,1181,1182],{"class":100,"line":513},[98,1183,181],{"class":1050},[98,1185,1186],{"class":100,"line":519},[98,1187,1188],{"class":1050},"**\u002F\n",[13,1190,1191,1192,1195],{},"上記データの ",[28,1193,1194],{},"DATA_FROM_DB.todo"," の変更前のデータを確認できるようにする必要があります。実装のためには別の定数なりに格納しておく必要があります。私はもちろん「参照渡し」・「値渡し」の概念は知っていたので、",[13,1197,1198],{},[28,1199,1200],{},"const OLD_TODO_DATA = DATA_FROM_DB.todo;",[13,1202,1203],{},"なんてことせず、",[13,1205,1206],{},[28,1207,1208],{},"const OLD_TODO_DATA = [...DATA_FROM_DB.todo];",[13,1210,1211],{},"とスプレッド構文を使用して新しく配列を生成しました。これで大丈夫だろと思っていましたが。。",[33,1213,1215],{"id":1214},"事件は起きた","事件は起きた。",[13,1217,1218,1219,1222],{},"新しいTODOと元のTODOを画面上に表示させて、TODO編集をテストしていた時です。新しくTODOを変更しているはずなに、古い ",[28,1220,1221],{},"OLD_TODO_DATA","から表示している内容も同じ変更した値に切り替わっていました。つまり値が連動していたのです。「WHY?」と声を出してしまいました。開発ツールで見ていても同じ値になっていることが確認できました。値が参照渡しされているとすぐに気づきましたが、「スプレッド構文を使用したのに...」と対処方法ずっと考えていました。",[1224,1225,1229,1230,1235],"div",{"className":1226},[1227,1228],"alert","alert-info","\nここでは値渡しと参照渡しの概念は解説しません。知らない方は",[196,1231,1234],{"target":1232,"href":1233},"_blank","https:\u002F\u002Fwww.google.com\u002Fsearch?q=js+%E5%80%A4%E6%B8%A1%E3%81%97+%E5%8F%82%E7%85%A7%E6%B8%A1%E3%81%97&oq=js+%E5%80%A4%E6%B8%A1%E3%81%97+%E5%8F%82%E7%85%A7%E6%B8%A1%E3%81%97&aqs=chrome..69i57.290j0j7&sourceid=chrome&ie=UTF-8","「js 値渡し 参照渡し」","でググってください。\n",[17,1237,1063],{"id":1063},[13,1239,1240,1241,1245],{},"原因は内包されたオブジェクトが参照渡しされていたからなのです。スプレッド構文は使用しましたが、これはあくまで",[1242,1243,1244],"strong",{},"別の配列","を作っただけであり、中身のオブジェクトの参照は維持されて（コピー元を参照して）いたのです。",[13,1247,1248],{},"以下のような実験をコンソールでしてみます。",[71,1250,1252],{"className":898,"code":1251,"filename":1115,"language":900,"meta":79,"style":79},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const passbyval = origin;\n\n> const spred = [...origin];\n\n> origin === passbyval;\n\u002F\u002F true\n\n> origin === spred;\n\u002F\u002F false\n\n> origin[0] === spred[0];\n\u002F\u002F true\n\u002F\u002F WHY!?\n",[28,1253,1254,1322,1326,1342,1346,1367,1371,1385,1390,1394,1407,1412,1416,1440,1444],{"__ignoreMap":79},[98,1255,1256,1259,1262,1265,1267,1270,1273,1275,1277,1279,1281,1283,1285,1287,1290,1292,1295,1297,1299,1301,1303,1305,1307,1309,1312,1314,1317,1320],{"class":100,"line":101},[98,1257,1258],{"class":915},">",[98,1260,1261],{"class":907}," const",[98,1263,1264],{"class":911}," origin ",[98,1266,916],{"class":915},[98,1268,1269],{"class":911},"[",[98,1271,1272],{"class":915},"{",[98,1274,928],{"class":927},[98,1276,931],{"class":915},[98,1278,935],{"class":934},[98,1280,938],{"class":915},[98,1282,957],{"class":927},[98,1284,931],{"class":915},[98,1286,946],{"class":915},[98,1288,1289],{"class":949},"1111",[98,1291,946],{"class":915},[98,1293,1294],{"class":915},"},{",[98,1296,928],{"class":927},[98,1298,931],{"class":915},[98,1300,980],{"class":934},[98,1302,938],{"class":915},[98,1304,957],{"class":927},[98,1306,931],{"class":915},[98,1308,946],{"class":915},[98,1310,1311],{"class":949},"2222",[98,1313,946],{"class":915},[98,1315,1316],{"class":915},"}",[98,1318,1319],{"class":911},"]",[98,1321,1106],{"class":915},[98,1323,1324],{"class":100,"line":107},[98,1325,389],{"emptyLinePlaceholder":348},[98,1327,1328,1330,1332,1335,1337,1340],{"class":100,"line":113},[98,1329,1258],{"class":915},[98,1331,1261],{"class":907},[98,1333,1334],{"class":911}," passbyval ",[98,1336,916],{"class":915},[98,1338,1339],{"class":911}," origin",[98,1341,1106],{"class":915},[98,1343,1344],{"class":100,"line":119},[98,1345,389],{"emptyLinePlaceholder":348},[98,1347,1348,1350,1352,1355,1357,1360,1362,1365],{"class":100,"line":125},[98,1349,1258],{"class":915},[98,1351,1261],{"class":907},[98,1353,1354],{"class":911}," spred ",[98,1356,916],{"class":915},[98,1358,1359],{"class":911}," [",[98,1361,964],{"class":915},[98,1363,1364],{"class":911},"origin]",[98,1366,1106],{"class":915},[98,1368,1369],{"class":100,"line":131},[98,1370,389],{"emptyLinePlaceholder":348},[98,1372,1373,1375,1377,1380,1383],{"class":100,"line":137},[98,1374,1258],{"class":915},[98,1376,1264],{"class":911},[98,1378,1379],{"class":915},"===",[98,1381,1382],{"class":911}," passbyval",[98,1384,1106],{"class":915},[98,1386,1387],{"class":100,"line":143},[98,1388,1389],{"class":1050},"\u002F\u002F true\n",[98,1391,1392],{"class":100,"line":149},[98,1393,389],{"emptyLinePlaceholder":348},[98,1395,1396,1398,1400,1402,1405],{"class":100,"line":155},[98,1397,1258],{"class":915},[98,1399,1264],{"class":911},[98,1401,1379],{"class":915},[98,1403,1404],{"class":911}," spred",[98,1406,1106],{"class":915},[98,1408,1409],{"class":100,"line":161},[98,1410,1411],{"class":1050},"\u002F\u002F false\n",[98,1413,1414],{"class":100,"line":166},[98,1415,389],{"emptyLinePlaceholder":348},[98,1417,1418,1420,1423,1426,1429,1431,1434,1436,1438],{"class":100,"line":172},[98,1419,1258],{"class":915},[98,1421,1422],{"class":911}," origin[",[98,1424,1425],{"class":934},"0",[98,1427,1428],{"class":911},"] ",[98,1430,1379],{"class":915},[98,1432,1433],{"class":911}," spred[",[98,1435,1425],{"class":934},[98,1437,1319],{"class":911},[98,1439,1106],{"class":915},[98,1441,1442],{"class":100,"line":178},[98,1443,1389],{"class":1050},[98,1445,1446],{"class":100,"line":513},[98,1447,1448],{"class":1050},"\u002F\u002F WHY!?\n",[13,1450,1451,1452,1455,1456,1459,1460,1463,1464,1467,1468,1471],{},"上記が示すとおり、スプレッド構文を使用することで配列としては別物の",[28,1453,1454],{},"origin === copy"," は",[28,1457,1458],{},"false","となり、値渡しの",[28,1461,1462],{},"origin === passbyval ","は",[28,1465,1466],{},"true","となります。ただし同じindexのオブジェクトを比較すると、なんと同じになっています。値を変えてみると",[28,1469,1470],{},"spred","も変更されているのが分かります。",[71,1473,1475],{"className":898,"code":1474,"filename":1115,"language":900,"meta":79,"style":79},"> origin[0].content = \"changed!\";\n\n> spred[0];\n\u002F\u002F {id: 1, content: 'changed!'}\n\u002F\u002F contentが変更されている\n",[28,1476,1477,1504,1508,1520,1525],{"__ignoreMap":79},[98,1478,1479,1481,1483,1485,1487,1489,1492,1494,1497,1500,1502],{"class":100,"line":101},[98,1480,1258],{"class":915},[98,1482,1422],{"class":911},[98,1484,1425],{"class":934},[98,1486,1319],{"class":911},[98,1488,1100],{"class":915},[98,1490,1491],{"class":911},"content ",[98,1493,916],{"class":915},[98,1495,1496],{"class":915}," \"",[98,1498,1499],{"class":949},"changed!",[98,1501,946],{"class":915},[98,1503,1106],{"class":915},[98,1505,1506],{"class":100,"line":107},[98,1507,389],{"emptyLinePlaceholder":348},[98,1509,1510,1512,1514,1516,1518],{"class":100,"line":113},[98,1511,1258],{"class":915},[98,1513,1433],{"class":911},[98,1515,1425],{"class":934},[98,1517,1319],{"class":911},[98,1519,1106],{"class":915},[98,1521,1522],{"class":100,"line":119},[98,1523,1524],{"class":1050},"\u002F\u002F {id: 1, content: 'changed!'}\n",[98,1526,1527],{"class":100,"line":125},[98,1528,1529],{"class":1050},"\u002F\u002F contentが変更されている\n",[13,1531,1532],{},"これが今回起きた原因です。つまり一応スプレッド構文を使用するのは配列の値をコピーするのでは確かに正しいのですが、今回のようなオブジェクトが内包されている場合は別の手法が必要です。",[17,1534,1068],{"id":1068},[13,1536,1537],{},"さて上記のように配列にオブジェクトが内包されている場合は、オブジェクトの参照が維持されたままになるのは確認できました。ではスプレッド構文以外にどうやって中身を値渡しできるでしょうか？",[13,1539,1540],{},"この時とられる方法としては「ディープコピー」があります。今回のように配列内のオブジェクトも値渡ししたいとき、つまり配列の中の深いとこまでマルッと別物としてコピーする処理をディープコピーと言います。",[1224,1542,1545,1546,1549],{"className":1543},[1227,1544],"alert-warning","\nvanilla ES6に",[28,1547,1548],{},"Array.prototype.deepcopy()","みたいなディープコピーを一発で行う関数はありません。以下の３つテクニックを使用します。\n",[33,1551,1553],{"id":1552},"_1jsonstringifyを使う","1:JSON.stringifyを使う",[13,1555,1556,1557,1560,1561,1564],{},"手取り早いのは",[28,1558,1559],{},"JSON.stringify()","を使用してコピー元をJSONにして、すぐに",[28,1562,1563],{},"JSON.parse()","を使用して元に戻します。この際、デコードしたJSONは全く新しい値となるので参照を断ち切ることができます。",[71,1566,1568],{"className":898,"code":1567,"filename":1115,"language":900,"meta":79,"style":79},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const copyjson = JSON.prase(JSON.stringify(origin));\n\n> copyjson;\n\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n\n> origin === copyjson;\n\u002F\u002F false\n\n> origin[0] === copyjson[0]\n\u002F\u002F false\n\u002F\u002F よし！\n",[28,1569,1570,1628,1632,1664,1668,1677,1682,1686,1698,1702,1706,1725,1729],{"__ignoreMap":79},[98,1571,1572,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594,1596,1598,1600,1602,1604,1606,1608,1610,1612,1614,1616,1618,1620,1622,1624,1626],{"class":100,"line":101},[98,1573,1258],{"class":915},[98,1575,1261],{"class":907},[98,1577,1264],{"class":911},[98,1579,916],{"class":915},[98,1581,1269],{"class":911},[98,1583,1272],{"class":915},[98,1585,928],{"class":927},[98,1587,931],{"class":915},[98,1589,935],{"class":934},[98,1591,938],{"class":915},[98,1593,957],{"class":927},[98,1595,931],{"class":915},[98,1597,946],{"class":915},[98,1599,1289],{"class":949},[98,1601,946],{"class":915},[98,1603,1294],{"class":915},[98,1605,928],{"class":927},[98,1607,931],{"class":915},[98,1609,980],{"class":934},[98,1611,938],{"class":915},[98,1613,957],{"class":927},[98,1615,931],{"class":915},[98,1617,946],{"class":915},[98,1619,1311],{"class":949},[98,1621,946],{"class":915},[98,1623,1316],{"class":915},[98,1625,1319],{"class":911},[98,1627,1106],{"class":915},[98,1629,1630],{"class":100,"line":107},[98,1631,389],{"emptyLinePlaceholder":348},[98,1633,1634,1636,1638,1641,1643,1646,1648,1651,1654,1656,1659,1662],{"class":100,"line":113},[98,1635,1258],{"class":915},[98,1637,1261],{"class":907},[98,1639,1640],{"class":911}," copyjson ",[98,1642,916],{"class":915},[98,1644,1645],{"class":911}," JSON",[98,1647,1100],{"class":915},[98,1649,1650],{"class":1120},"prase",[98,1652,1653],{"class":911},"(JSON",[98,1655,1100],{"class":915},[98,1657,1658],{"class":1120},"stringify",[98,1660,1661],{"class":911},"(origin))",[98,1663,1106],{"class":915},[98,1665,1666],{"class":100,"line":119},[98,1667,389],{"emptyLinePlaceholder":348},[98,1669,1670,1672,1675],{"class":100,"line":125},[98,1671,1258],{"class":915},[98,1673,1674],{"class":911}," copyjson",[98,1676,1106],{"class":915},[98,1678,1679],{"class":100,"line":131},[98,1680,1681],{"class":1050},"\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n",[98,1683,1684],{"class":100,"line":137},[98,1685,389],{"emptyLinePlaceholder":348},[98,1687,1688,1690,1692,1694,1696],{"class":100,"line":143},[98,1689,1258],{"class":915},[98,1691,1264],{"class":911},[98,1693,1379],{"class":915},[98,1695,1674],{"class":911},[98,1697,1106],{"class":915},[98,1699,1700],{"class":100,"line":149},[98,1701,1411],{"class":1050},[98,1703,1704],{"class":100,"line":155},[98,1705,389],{"emptyLinePlaceholder":348},[98,1707,1708,1710,1712,1714,1716,1718,1721,1723],{"class":100,"line":161},[98,1709,1258],{"class":915},[98,1711,1422],{"class":911},[98,1713,1425],{"class":934},[98,1715,1428],{"class":911},[98,1717,1379],{"class":915},[98,1719,1720],{"class":911}," copyjson[",[98,1722,1425],{"class":934},[98,1724,1056],{"class":911},[98,1726,1727],{"class":100,"line":166},[98,1728,1411],{"class":1050},[98,1730,1731],{"class":100,"line":172},[98,1732,1733],{"class":1050},"\u002F\u002F よし！\n",[13,1735,1736],{},"JSONエンコードしてデコードする必要はありますが、中身がなんであろうが関係なく展開できるのは良いところです。",[33,1738,1740],{"id":1739},"_2スプレッドとmapを組み合わせる使用箇所が限定的なので微妙","2:スプレッドとmap()を組み合わせる（使用箇所が限定的なので微妙）",[13,1742,1743,1744,1751],{},"スプレッド構文はオブジェクトにも使用できます。しかし今回は配列内にいるのが厄介です。そんな時は ",[196,1745,1748],{"href":1746,"rel":1747},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FArray\u002Fmap",[200],[28,1749,1750],{},"map()","を使用して各々のオブジェクトを展開して、新しい配列を生成します。",[71,1753,1755],{"className":898,"code":1754,"filename":1115,"language":900,"meta":79,"style":79},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const copymap = origin.map(obj => {return {...obj}});\n\n> copymap;\n\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n\n> origin === copymap;\n\u002F\u002F false\n\n> origin[0] === copymap[0]\n\u002F\u002F false\n\u002F\u002F よし！\n",[28,1756,1757,1815,1819,1867,1871,1880,1884,1888,1900,1904,1908,1927,1931],{"__ignoreMap":79},[98,1758,1759,1761,1763,1765,1767,1769,1771,1773,1775,1777,1779,1781,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803,1805,1807,1809,1811,1813],{"class":100,"line":101},[98,1760,1258],{"class":915},[98,1762,1261],{"class":907},[98,1764,1264],{"class":911},[98,1766,916],{"class":915},[98,1768,1269],{"class":911},[98,1770,1272],{"class":915},[98,1772,928],{"class":927},[98,1774,931],{"class":915},[98,1776,935],{"class":934},[98,1778,938],{"class":915},[98,1780,957],{"class":927},[98,1782,931],{"class":915},[98,1784,946],{"class":915},[98,1786,1289],{"class":949},[98,1788,946],{"class":915},[98,1790,1294],{"class":915},[98,1792,928],{"class":927},[98,1794,931],{"class":915},[98,1796,980],{"class":934},[98,1798,938],{"class":915},[98,1800,957],{"class":927},[98,1802,931],{"class":915},[98,1804,946],{"class":915},[98,1806,1311],{"class":949},[98,1808,946],{"class":915},[98,1810,1316],{"class":915},[98,1812,1319],{"class":911},[98,1814,1106],{"class":915},[98,1816,1817],{"class":100,"line":107},[98,1818,389],{"emptyLinePlaceholder":348},[98,1820,1821,1823,1825,1828,1830,1832,1834,1837,1840,1844,1847,1850,1854,1857,1859,1862,1865],{"class":100,"line":113},[98,1822,1258],{"class":915},[98,1824,1261],{"class":907},[98,1826,1827],{"class":911}," copymap ",[98,1829,916],{"class":915},[98,1831,1339],{"class":911},[98,1833,1100],{"class":915},[98,1835,1836],{"class":1120},"map",[98,1838,1839],{"class":911},"(",[98,1841,1843],{"class":1842},"s7ZW3","obj",[98,1845,1846],{"class":907}," =>",[98,1848,1849],{"class":915}," {",[98,1851,1853],{"class":1852},"s6cf3","return",[98,1855,1856],{"class":915}," {...",[98,1858,1843],{"class":911},[98,1860,1861],{"class":915},"}}",[98,1863,1864],{"class":911},")",[98,1866,1106],{"class":915},[98,1868,1869],{"class":100,"line":119},[98,1870,389],{"emptyLinePlaceholder":348},[98,1872,1873,1875,1878],{"class":100,"line":125},[98,1874,1258],{"class":915},[98,1876,1877],{"class":911}," copymap",[98,1879,1106],{"class":915},[98,1881,1882],{"class":100,"line":131},[98,1883,1681],{"class":1050},[98,1885,1886],{"class":100,"line":137},[98,1887,389],{"emptyLinePlaceholder":348},[98,1889,1890,1892,1894,1896,1898],{"class":100,"line":143},[98,1891,1258],{"class":915},[98,1893,1264],{"class":911},[98,1895,1379],{"class":915},[98,1897,1877],{"class":911},[98,1899,1106],{"class":915},[98,1901,1902],{"class":100,"line":149},[98,1903,1411],{"class":1050},[98,1905,1906],{"class":100,"line":155},[98,1907,389],{"emptyLinePlaceholder":348},[98,1909,1910,1912,1914,1916,1918,1920,1923,1925],{"class":100,"line":161},[98,1911,1258],{"class":915},[98,1913,1422],{"class":911},[98,1915,1425],{"class":934},[98,1917,1428],{"class":911},[98,1919,1379],{"class":915},[98,1921,1922],{"class":911}," copymap[",[98,1924,1425],{"class":934},[98,1926,1056],{"class":911},[98,1928,1929],{"class":100,"line":166},[98,1930,1411],{"class":1050},[98,1932,1933],{"class":100,"line":172},[98,1934,1733],{"class":1050},[13,1936,1937,1938,1941],{},"JSONを使うよりスマートですが、配列内がオブジェクト・配列といったiterableなものでないと使えません。今使用した",[28,1939,1940],{},"origin","のような簡単な構成であればいいですが、途中で文字列があったりなど、中身が全てiterableである保証がない場合はエラーが起きる可能性があります。あと以下の様にオブジェクトの中にオブジェクトがあるネストした場合はディープコピーできません！！",[71,1943,1945],{"className":898,"code":1944,"filename":1115,"language":900,"meta":79,"style":79},"> const origin =[{id:1,content:{summery:\"detail1\",detail:\"detail1\"}},{id:2,content:{summery:\"detail2\",detail:\"detail2\"}},];\n\n> const copymap = origin.map(obj => {return {...obj}});\n\n> origin[0] === copymap[0]\n\u002F\u002F false\n\n> origin[0].content === copymap[0].content;\n\u002F\u002F true\n\u002F\u002F んっっ！？\n",[28,1946,1947,2044,2048,2084,2088,2106,2110,2114,2142,2146],{"__ignoreMap":79},[98,1948,1949,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1974,1977,1979,1981,1984,1986,1988,1991,1993,1995,1997,1999,2002,2004,2006,2008,2010,2012,2014,2016,2018,2020,2023,2025,2027,2029,2031,2033,2035,2037,2040,2042],{"class":100,"line":101},[98,1950,1258],{"class":915},[98,1952,1261],{"class":907},[98,1954,1264],{"class":911},[98,1956,916],{"class":915},[98,1958,1269],{"class":911},[98,1960,1272],{"class":915},[98,1962,928],{"class":927},[98,1964,931],{"class":915},[98,1966,935],{"class":934},[98,1968,938],{"class":915},[98,1970,957],{"class":927},[98,1972,1973],{"class":915},":{",[98,1975,1976],{"class":927},"summery",[98,1978,931],{"class":915},[98,1980,946],{"class":915},[98,1982,1983],{"class":949},"detail1",[98,1985,946],{"class":915},[98,1987,938],{"class":915},[98,1989,1990],{"class":927},"detail",[98,1992,931],{"class":915},[98,1994,946],{"class":915},[98,1996,1983],{"class":949},[98,1998,946],{"class":915},[98,2000,2001],{"class":915},"}},{",[98,2003,928],{"class":927},[98,2005,931],{"class":915},[98,2007,980],{"class":934},[98,2009,938],{"class":915},[98,2011,957],{"class":927},[98,2013,1973],{"class":915},[98,2015,1976],{"class":927},[98,2017,931],{"class":915},[98,2019,946],{"class":915},[98,2021,2022],{"class":949},"detail2",[98,2024,946],{"class":915},[98,2026,938],{"class":915},[98,2028,1990],{"class":927},[98,2030,931],{"class":915},[98,2032,946],{"class":915},[98,2034,2022],{"class":949},[98,2036,946],{"class":915},[98,2038,2039],{"class":915},"}},",[98,2041,1319],{"class":911},[98,2043,1106],{"class":915},[98,2045,2046],{"class":100,"line":107},[98,2047,389],{"emptyLinePlaceholder":348},[98,2049,2050,2052,2054,2056,2058,2060,2062,2064,2066,2068,2070,2072,2074,2076,2078,2080,2082],{"class":100,"line":113},[98,2051,1258],{"class":915},[98,2053,1261],{"class":907},[98,2055,1827],{"class":911},[98,2057,916],{"class":915},[98,2059,1339],{"class":911},[98,2061,1100],{"class":915},[98,2063,1836],{"class":1120},[98,2065,1839],{"class":911},[98,2067,1843],{"class":1842},[98,2069,1846],{"class":907},[98,2071,1849],{"class":915},[98,2073,1853],{"class":1852},[98,2075,1856],{"class":915},[98,2077,1843],{"class":911},[98,2079,1861],{"class":915},[98,2081,1864],{"class":911},[98,2083,1106],{"class":915},[98,2085,2086],{"class":100,"line":119},[98,2087,389],{"emptyLinePlaceholder":348},[98,2089,2090,2092,2094,2096,2098,2100,2102,2104],{"class":100,"line":125},[98,2091,1258],{"class":915},[98,2093,1422],{"class":911},[98,2095,1425],{"class":934},[98,2097,1428],{"class":911},[98,2099,1379],{"class":915},[98,2101,1922],{"class":911},[98,2103,1425],{"class":934},[98,2105,1056],{"class":911},[98,2107,2108],{"class":100,"line":131},[98,2109,1411],{"class":1050},[98,2111,2112],{"class":100,"line":137},[98,2113,389],{"emptyLinePlaceholder":348},[98,2115,2116,2118,2120,2122,2124,2126,2128,2130,2132,2134,2136,2138,2140],{"class":100,"line":143},[98,2117,1258],{"class":915},[98,2119,1422],{"class":911},[98,2121,1425],{"class":934},[98,2123,1319],{"class":911},[98,2125,1100],{"class":915},[98,2127,1491],{"class":911},[98,2129,1379],{"class":915},[98,2131,1922],{"class":911},[98,2133,1425],{"class":934},[98,2135,1319],{"class":911},[98,2137,1100],{"class":915},[98,2139,957],{"class":911},[98,2141,1106],{"class":915},[98,2143,2144],{"class":100,"line":149},[98,2145,1389],{"class":1050},[98,2147,2148],{"class":100,"line":155},[98,2149,2150],{"class":1050},"\u002F\u002F んっっ！？\n",[13,2152,2153],{},"なのでこのmapとスプレッドは使うのは結構微妙です。",[33,2155,2157],{"id":2156},"_3lodashのclonedeepを使用する","3:lodashのcloneDeep()を使用する",[13,2159,2160,2161,2164,2165,2167],{},"テクニックではないのですがlodashなどのライブラリを用いると、",[28,2162,2163],{},"cloneDeep()","といったディープコピー を行うユーティリティー関数があります。面倒な場合はそれを使ってしまってもいいと思います。なんか方法１のJSONよりもlodashの",[28,2166,2163],{},"の方が早いみたいです。",[13,2169,2170],{},[196,2171,2174],{"href":2172,"rel":2173},"https:\u002F\u002Fqiita.com\u002Fsuin\u002Fitems\u002F80e687dd1789b9d9d2fd",[200],"参考：JavaScriptのディープコピー速さ比較 〜7つの手法\u002Fライブラリを比べてみた〜",[71,2176,2178],{"className":898,"code":2177,"filename":1115,"language":900,"meta":79,"style":79},"> const origin =[{id:1,content:{summery:\"detail1\",detail:\"detail1\"}},{id:2,content:{summery:\"detail2\",detail:\"detail2\"}},];\n\n> const copy_ =  _.cloneDeep(origin);\n\n> origin[0] === copy_[0]\n\u002F\u002F false\n\n> origin[0].content === copy_[0].content;\n\u002F\u002F false\n\u002F\u002F よし！\n",[28,2179,2180,2270,2274,2298,2302,2321,2325,2329,2357,2361],{"__ignoreMap":79},[98,2181,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2224,2226,2228,2230,2232,2234,2236,2238,2240,2242,2244,2246,2248,2250,2252,2254,2256,2258,2260,2262,2264,2266,2268],{"class":100,"line":101},[98,2183,1258],{"class":915},[98,2185,1261],{"class":907},[98,2187,1264],{"class":911},[98,2189,916],{"class":915},[98,2191,1269],{"class":911},[98,2193,1272],{"class":915},[98,2195,928],{"class":927},[98,2197,931],{"class":915},[98,2199,935],{"class":934},[98,2201,938],{"class":915},[98,2203,957],{"class":927},[98,2205,1973],{"class":915},[98,2207,1976],{"class":927},[98,2209,931],{"class":915},[98,2211,946],{"class":915},[98,2213,1983],{"class":949},[98,2215,946],{"class":915},[98,2217,938],{"class":915},[98,2219,1990],{"class":927},[98,2221,931],{"class":915},[98,2223,946],{"class":915},[98,2225,1983],{"class":949},[98,2227,946],{"class":915},[98,2229,2001],{"class":915},[98,2231,928],{"class":927},[98,2233,931],{"class":915},[98,2235,980],{"class":934},[98,2237,938],{"class":915},[98,2239,957],{"class":927},[98,2241,1973],{"class":915},[98,2243,1976],{"class":927},[98,2245,931],{"class":915},[98,2247,946],{"class":915},[98,2249,2022],{"class":949},[98,2251,946],{"class":915},[98,2253,938],{"class":915},[98,2255,1990],{"class":927},[98,2257,931],{"class":915},[98,2259,946],{"class":915},[98,2261,2022],{"class":949},[98,2263,946],{"class":915},[98,2265,2039],{"class":915},[98,2267,1319],{"class":911},[98,2269,1106],{"class":915},[98,2271,2272],{"class":100,"line":107},[98,2273,389],{"emptyLinePlaceholder":348},[98,2275,2276,2278,2280,2283,2285,2288,2290,2293,2296],{"class":100,"line":113},[98,2277,1258],{"class":915},[98,2279,1261],{"class":907},[98,2281,2282],{"class":911}," copy_ ",[98,2284,916],{"class":915},[98,2286,2287],{"class":911},"  _",[98,2289,1100],{"class":915},[98,2291,2292],{"class":1120},"cloneDeep",[98,2294,2295],{"class":911},"(origin)",[98,2297,1106],{"class":915},[98,2299,2300],{"class":100,"line":119},[98,2301,389],{"emptyLinePlaceholder":348},[98,2303,2304,2306,2308,2310,2312,2314,2317,2319],{"class":100,"line":125},[98,2305,1258],{"class":915},[98,2307,1422],{"class":911},[98,2309,1425],{"class":934},[98,2311,1428],{"class":911},[98,2313,1379],{"class":915},[98,2315,2316],{"class":911}," copy_[",[98,2318,1425],{"class":934},[98,2320,1056],{"class":911},[98,2322,2323],{"class":100,"line":131},[98,2324,1411],{"class":1050},[98,2326,2327],{"class":100,"line":137},[98,2328,389],{"emptyLinePlaceholder":348},[98,2330,2331,2333,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353,2355],{"class":100,"line":143},[98,2332,1258],{"class":915},[98,2334,1422],{"class":911},[98,2336,1425],{"class":934},[98,2338,1319],{"class":911},[98,2340,1100],{"class":915},[98,2342,1491],{"class":911},[98,2344,1379],{"class":915},[98,2346,2316],{"class":911},[98,2348,1425],{"class":934},[98,2350,1319],{"class":911},[98,2352,1100],{"class":915},[98,2354,957],{"class":911},[98,2356,1106],{"class":915},[98,2358,2359],{"class":100,"line":149},[98,2360,1411],{"class":1050},[98,2362,2363],{"class":100,"line":155},[98,2364,1733],{"class":1050},[13,2366,2367],{},"ちなみに方法１のJSONもネストしたオブジェクトの参照は断ち切れます。",[17,2369,2371],{"id":2370},"ライブラリかjson変換を使うといい","ライブラリかJSON変換を使うといい",[13,2373,2374],{},"以上が配列内のオブジェクトの値が連動してしまう原因と対処法です。正確には配列内にオブジェクトを含む場合や、オブジェクト内にオブジェクトを含む値コピーする時は「ディープコピー 」を使いましょうというお話です。ネストしたオブジェクトは今回解説した様に、参照が根深く残っています。アプリによっては以下のような単純な構造でなく、",[71,2376,2378],{"className":898,"code":2377,"language":900,"meta":79,"style":79},"[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n",[28,2379,2380],{"__ignoreMap":79},[98,2381,2382,2384,2386,2388,2390,2392,2394,2396,2398,2400,2402,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422,2424,2426,2428],{"class":100,"line":101},[98,2383,1269],{"class":911},[98,2385,1272],{"class":915},[98,2387,928],{"class":927},[98,2389,931],{"class":915},[98,2391,935],{"class":934},[98,2393,938],{"class":915},[98,2395,957],{"class":927},[98,2397,931],{"class":915},[98,2399,946],{"class":915},[98,2401,1289],{"class":949},[98,2403,946],{"class":915},[98,2405,1294],{"class":915},[98,2407,928],{"class":927},[98,2409,931],{"class":915},[98,2411,980],{"class":934},[98,2413,938],{"class":915},[98,2415,957],{"class":927},[98,2417,931],{"class":915},[98,2419,946],{"class":915},[98,2421,1311],{"class":949},[98,2423,946],{"class":915},[98,2425,1316],{"class":915},[98,2427,1319],{"class":911},[98,2429,1106],{"class":915},[13,2431,2432],{},"以下のように内包する値も複雑で、さらにオブジェクトがネストしていることもあります。",[71,2434,2436],{"className":898,"code":2435,"language":900,"meta":79,"style":79},"const origin = {\n    title: \"...\", \u002F\u002F 途中にiterableでないものがある。\n    todo:[\n            {\n                id:1,\n                \u002F\u002F オブジェクトがネストしている\n                content:{\n                    summery:\"detail1\",detail:\"detail1\"\n                }\n            },\n            {\n                id:2,\n                content:{\n                    summery:\"detail2\",detail:\"detail2\"\n                }\n            }\n        ];\n    \u002F\u002F More unpredictable properties..\n}\n",[28,2437,2438,2449,2467,2477,2482,2494,2499,2507,2533,2538,2543,2547,2557,2563,2587,2591,2596,2601,2606],{"__ignoreMap":79},[98,2439,2440,2442,2444,2446],{"class":100,"line":101},[98,2441,908],{"class":907},[98,2443,1264],{"class":911},[98,2445,916],{"class":915},[98,2447,2448],{"class":915}," {\n",[98,2450,2451,2454,2456,2458,2460,2462,2464],{"class":100,"line":107},[98,2452,2453],{"class":927},"    title",[98,2455,931],{"class":915},[98,2457,1496],{"class":915},[98,2459,964],{"class":949},[98,2461,946],{"class":915},[98,2463,938],{"class":915},[98,2465,2466],{"class":1050}," \u002F\u002F 途中にiterableでないものがある。\n",[98,2468,2469,2472,2474],{"class":100,"line":113},[98,2470,2471],{"class":927},"    todo",[98,2473,931],{"class":915},[98,2475,2476],{"class":911},"[\n",[98,2478,2479],{"class":100,"line":119},[98,2480,2481],{"class":915},"            {\n",[98,2483,2484,2487,2489,2491],{"class":100,"line":125},[98,2485,2486],{"class":927},"                id",[98,2488,931],{"class":915},[98,2490,935],{"class":934},[98,2492,2493],{"class":915},",\n",[98,2495,2496],{"class":100,"line":131},[98,2497,2498],{"class":1050},"                \u002F\u002F オブジェクトがネストしている\n",[98,2500,2501,2504],{"class":100,"line":137},[98,2502,2503],{"class":927},"                content",[98,2505,2506],{"class":915},":{\n",[98,2508,2509,2512,2514,2516,2518,2520,2522,2524,2526,2528,2530],{"class":100,"line":143},[98,2510,2511],{"class":927},"                    summery",[98,2513,931],{"class":915},[98,2515,946],{"class":915},[98,2517,1983],{"class":949},[98,2519,946],{"class":915},[98,2521,938],{"class":915},[98,2523,1990],{"class":927},[98,2525,931],{"class":915},[98,2527,946],{"class":915},[98,2529,1983],{"class":949},[98,2531,2532],{"class":915},"\"\n",[98,2534,2535],{"class":100,"line":149},[98,2536,2537],{"class":915},"                }\n",[98,2539,2540],{"class":100,"line":155},[98,2541,2542],{"class":915},"            },\n",[98,2544,2545],{"class":100,"line":161},[98,2546,2481],{"class":915},[98,2548,2549,2551,2553,2555],{"class":100,"line":166},[98,2550,2486],{"class":927},[98,2552,931],{"class":915},[98,2554,980],{"class":934},[98,2556,2493],{"class":915},[98,2558,2559,2561],{"class":100,"line":172},[98,2560,2503],{"class":927},[98,2562,2506],{"class":915},[98,2564,2565,2567,2569,2571,2573,2575,2577,2579,2581,2583,2585],{"class":100,"line":178},[98,2566,2511],{"class":927},[98,2568,931],{"class":915},[98,2570,946],{"class":915},[98,2572,2022],{"class":949},[98,2574,946],{"class":915},[98,2576,938],{"class":915},[98,2578,1990],{"class":927},[98,2580,931],{"class":915},[98,2582,946],{"class":915},[98,2584,2022],{"class":949},[98,2586,2532],{"class":915},[98,2588,2589],{"class":100,"line":513},[98,2590,2537],{"class":915},[98,2592,2593],{"class":100,"line":519},[98,2594,2595],{"class":915},"            }\n",[98,2597,2598],{"class":100,"line":525},[98,2599,2600],{"class":911},"        ];\n",[98,2602,2603],{"class":100,"line":531},[98,2604,2605],{"class":1050},"    \u002F\u002F More unpredictable properties..\n",[98,2607,2608],{"class":100,"line":537},[98,2609,181],{"class":915},[13,2611,2612],{},"上記のような状況を踏まえると、ディープコピー はJSONを用いるか大人しくライブラリを使用する方が賢明そうです。値が連動してしまう時はまず値渡し・参照渡しを疑い、その次はディープコピーがされているか（ネストしたオブジェクトがないか）を確かめてみましょう。",[328,2614,2615],{},"html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}",{"title":79,"searchDepth":113,"depth":113,"links":2617},[2618,2621,2622,2627],{"id":1072,"depth":107,"text":1072,"children":2619},[2620],{"id":1214,"depth":113,"text":1215},{"id":1063,"depth":107,"text":1063},{"id":1068,"depth":107,"text":1068,"children":2623},[2624,2625,2626],{"id":1552,"depth":113,"text":1553},{"id":1739,"depth":113,"text":1740},{"id":2156,"depth":113,"text":2157},{"id":2370,"depth":107,"text":2371},[342],"2021-11-07","配列内のオブジェクトの値が連動するときの原因と対処法",{},"\u002Farticles\u002Fjs-deep-copy",{"title":886,"description":2630},"articles\u002Fjs-deep-copy",[2636,2637],"js","vue","TVfFMZbaj-eg5y8hB-QhEPtPjdhOPFn6vmaY0JeSo0g",{"id":2640,"title":2641,"body":2642,"category":2849,"createdAt":2850,"description":2641,"extension":345,"index":346,"meta":2851,"navigation":348,"path":2852,"publish":348,"seo":2853,"series":346,"seriesTitle":346,"stem":2854,"tag":2855,"thumbnail":346,"updatedAt":346,"__hash__":2857},"articles\u002Farticles\u002Fpreflight-redirect-cors-error.md","URL正規化によって Redirect is not allowed for a preflight request でCORSエラーが起きた",{"type":10,"value":2643,"toc":2847},[2644,2647,2653,2660,2686,2700,2703,2824,2838,2844],[13,2645,2646],{},"こんにちはjunです。LaravelとNuxt SPAでアプリを作っていたのですがCORS設定をしているのに偶に以下のようなエラーが発生していました。",[71,2648,2651],{"className":2649,"code":2650,"language":76},[74],"Access to XMLHttpRequest at 'http:\u002F\u002Flocalhost\u002Fapi\u002Fv1\u002Ftest\u002F' from origin 'http:\u002F\u002Flocalhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.\n",[28,2652,2650],{"__ignoreMap":79},[13,2654,2655,2656,2659],{},"エラー内容の通り原因はpreflightリクエストがリダイレクトされてしまっていることが原因です。開発者ツールでnetworkを見ると確かにpreflightリクエストが301となっていることが原因です。しかしなぜリダイレクト？Laravelでredirectを返すメソッドがあるのかと思いましたが、原因は",[28,2657,2658],{},".htaccess","の以下の記述でした。",[71,2661,2664],{"className":2662,"code":2663,"language":2658,"meta":79,"style":79},"language-.htaccess shiki shiki-themes material-theme-ocean","#Redirect Trailing Slashes If Not A Folder...\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_URI} (.+)\u002F$\nRewriteRule ^ %1 [L,R=301]\n",[28,2665,2666,2671,2676,2681],{"__ignoreMap":79},[98,2667,2668],{"class":100,"line":101},[98,2669,2670],{},"#Redirect Trailing Slashes If Not A Folder...\n",[98,2672,2673],{"class":100,"line":107},[98,2674,2675],{},"RewriteCond %{REQUEST_FILENAME} !-d\n",[98,2677,2678],{"class":100,"line":113},[98,2679,2680],{},"RewriteCond %{REQUEST_URI} (.+)\u002F$\n",[98,2682,2683],{"class":100,"line":119},[98,2684,2685],{},"RewriteRule ^ %1 [L,R=301]\n",[13,2687,2688,2689,2691,2692,2695,2696,2699],{},"上記はLaravelが使用するURLの正規化を行う",[28,2690,2658],{},"の記述です。URLの末尾にスラッシュがある場合、ないように正規化してくれます。",[28,2693,2694],{},"http:\u002F\u002Flocalhost\u002Ftest\u002F","→",[28,2697,2698],{},"http:\u002F\u002Flocalhost\u002Ftest"," のようにリダイレクトがおきます。これはAPIルートでも発生します。",[13,2701,2702],{},"私のAPIリクエストを見てみると",[71,2704,2706],{"className":898,"code":2705,"language":900,"meta":79,"style":79},"async test(){\n    this.$axios.post('\u002Fv1\u002Ftest\b\u002F')\n    .then(res=>[\n        console.log(res)\n    ])\n    .catch(err=>{\n        console.log(err)\n    })\n}\n",[28,2707,2708,2721,2746,2764,2779,2783,2799,2813,2820],{"__ignoreMap":79},[98,2709,2710,2713,2716,2719],{"class":100,"line":101},[98,2711,2712],{"class":911},"async ",[98,2714,2715],{"class":1120},"test",[98,2717,2718],{"class":911},"()",[98,2720,140],{"class":915},[98,2722,2723,2726,2729,2731,2734,2736,2739,2742,2744],{"class":100,"line":107},[98,2724,2725],{"class":915},"    this.",[98,2727,2728],{"class":911},"$axios",[98,2730,1100],{"class":915},[98,2732,2733],{"class":1120},"post",[98,2735,1839],{"class":927},[98,2737,2738],{"class":915},"'",[98,2740,2741],{"class":949},"\u002Fv1\u002Ftest\b\u002F",[98,2743,2738],{"class":915},[98,2745,794],{"class":927},[98,2747,2748,2751,2754,2756,2759,2762],{"class":100,"line":113},[98,2749,2750],{"class":915},"    .",[98,2752,2753],{"class":1120},"then",[98,2755,1839],{"class":927},[98,2757,2758],{"class":1842},"res",[98,2760,2761],{"class":907},"=>",[98,2763,2476],{"class":927},[98,2765,2766,2769,2771,2773,2775,2777],{"class":100,"line":119},[98,2767,2768],{"class":911},"        console",[98,2770,1100],{"class":915},[98,2772,1121],{"class":1120},[98,2774,1839],{"class":927},[98,2776,2758],{"class":911},[98,2778,794],{"class":927},[98,2780,2781],{"class":100,"line":125},[98,2782,169],{"class":927},[98,2784,2785,2787,2790,2792,2795,2797],{"class":100,"line":131},[98,2786,2750],{"class":915},[98,2788,2789],{"class":1120},"catch",[98,2791,1839],{"class":927},[98,2793,2794],{"class":1842},"err",[98,2796,2761],{"class":907},[98,2798,140],{"class":915},[98,2800,2801,2803,2805,2807,2809,2811],{"class":100,"line":137},[98,2802,2768],{"class":911},[98,2804,1100],{"class":915},[98,2806,1121],{"class":1120},[98,2808,1839],{"class":927},[98,2810,2794],{"class":911},[98,2812,794],{"class":927},[98,2814,2815,2818],{"class":100,"line":143},[98,2816,2817],{"class":915},"    }",[98,2819,794],{"class":927},[98,2821,2822],{"class":100,"line":149},[98,2823,181],{"class":915},[13,2825,2826,2827,2829,2830,2833,2834,2837],{},"URLをみてみると",[28,2828,2741],{},"と末尾にスケジュール があります。そしてXHRは ",[28,2831,2832],{},"POST + contetnt-type:application\u002Fjson"," のようなリクエストではpreflightリクエストが飛びますが、そのリクエストはリダイレクトをしてはいけません。そのためURLを",[28,2835,2836],{},"\u002Fv1\u002Ftest\b","と末尾をなくしてあげたらリダイレクトが起きず、問題なくCORSが起きなくなりました。",[13,2839,2840,2841,2843],{},"CORSの設定やLaravelのメソッドを調べていましたが、結構簡単な",[28,2842,2658],{},"が原因でした。",[328,2845,2846],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}",{"title":79,"searchDepth":113,"depth":113,"links":2848},[],[342],"2021-09-19",{},"\u002Farticles\u002Fpreflight-redirect-cors-error",{"title":2641,"description":2641},"articles\u002Fpreflight-redirect-cors-error",[2856,354],"infrastructure","ia4jjF7K85Ze8kJeV-fqRUKhfJsuBqIgYCJYkocy2u0",{"id":2859,"title":2860,"body":2861,"category":3711,"createdAt":3712,"description":3713,"extension":345,"index":346,"meta":3714,"navigation":348,"path":3715,"publish":348,"seo":3716,"series":346,"seriesTitle":346,"stem":3717,"tag":3718,"thumbnail":346,"updatedAt":346,"__hash__":3720},"articles\u002Farticles\u002Fwp-batch-image-compress.md","大量の大ファイルサイズ画像をPHPでリサイズ・圧縮をする方法",{"type":10,"value":2862,"toc":3699},[2863,2866,2869,2872,2875,2878,2898,2901,2904,2907,3096,3106,3109,3113,3119,3151,3160,3209,3216,3220,3225,3234,3237,3306,3312,3315,3318,3321,3663,3670,3674,3681,3687,3690,3696],[13,2864,2865],{},"こんにちはjunです。私はこの技術ブログ以外にもブログを運営しているのですが、そちらはwebエンジニアになる前からやっていました。しかし過去の記事を見ているとやたらと重い画像、１枚あたり１MBも使っている記事が何枚もありました。当時は画像の重さなど知らずにデジカメの画像をそのままアップロードして、使用していたことが原因です。",[13,2867,2868],{},"記事の中には転送量が12MBにもなっているものもあり、原因は画像でした。それらの画像はやたらとサイズ（寸法）が大きいことが原因なので、リサイズして圧縮することで解決できます。しかし100件以上の記事を1つずつ開いて調べたり、もう一回ダウンロードして、圧縮してアップロードなんて何日かかるかわかりません。そのため今回はPHPとコマンドラインを用いて一気に画像を処理することにしました。",[13,2870,2871],{},"wordpressを使用していますが、画像処理のエッセンスや大方の処理の流れは応用できるとおもいます。では早速やっていきましょう。",[17,2873,2874],{"id":2874},"大まかな流れ",[13,2876,2877],{},"まず全体の処理の流れですが以下の通りです。",[2879,2880,2881,2889,2892,2895],"ol",{},[2882,2883,2884,2885,2888],"li",{},"ターミナルで ",[28,2886,2887],{},"wp-content\u002Fuploads\u002F"," 配下にある大サイズ（500kb以上とする）をリストアップ。",[2882,2890,2891],{},"バックアップしておき、数ヶ月残しておく。",[2882,2893,2894],{},"PHPのGDモジュールを用いてリサイズ・圧縮を行う。",[2882,2896,2897],{},"処理した画像を上書き。",[13,2899,2900],{},"以上の通りです。今回の処理を行うにあたりwordpressがあるサーバーに対してCLI\b操作が行える必要があります。SSHができ、必要な権限を付与しておいてください。今回はこの準備はできているものとします。",[17,2902,2903],{"id":2903},"処理対象をリストアップ",[13,2905,2906],{},"それではまず対象の画像をリストアップします。アップロードディレクトリに移動してfindコマンドで簡単に見つけられます。",[71,2908,2912],{"className":2909,"code":2910,"language":2911,"meta":79,"style":79},"language-bash shiki shiki-themes material-theme-ocean","# \u002Fdocumentroot\u002Fwordpress\u002F は仮です。あなたの環境に合わせてください。\n# 画像が格納されているuploadsへ移動\ncd '\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads'\nls\n2017 2018 2019 2020 2021 aaaa bbbbb cccc\n\n# プラグイン用画像のディレクトリなどもあるので注意！\n# 自分がアップロードした画像があるディレクトリのみを指定、500kb以上のものをリストアップ。リストはテキストファイルとしてホームディレクトリにおいておく。\nfind 2017 2018 2019 2020 2021 -size +500k > ~\u002Flist.txt\n..\n2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-644x279.png\n2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-720x340.png\n2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-768x332.png\n2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83.png\n2017\u002F12\u002FDSC03961-1200x900.jpg\n2017\u002F12\u002FDSC04310-1200x900.jpg\n2017\u002F12\u002FDSC04311-1200x900.jpg\n2017\u002F12\u002FDSC04314-1200x900.jpg\n2017\u002F12\u002FDSC04315-1200x900.jpg\n2017\u002F12\u002FDSC04316-1200x900.jpg\n2017\u002F12\u002FDSC04317-1200x900.jpg\n2017\u002F12\u002FDSC04319-1200x900.jpg\n2017\u002F12\u002FDSC04320-e1512559527929-1200x1600.jpg\n2017\u002F12\u002FDSC04324-1200x900.jpg\n2017\u002F12\u002FDSC04325-1200x900.jpg\n...\n","bash",[28,2913,2914,2919,2924,2938,2944,2970,2974,2979,2984,3012,3017,3022,3027,3032,3037,3042,3047,3052,3057,3062,3067,3072,3077,3082,3087,3092],{"__ignoreMap":79},[98,2915,2916],{"class":100,"line":101},[98,2917,2918],{"class":1050},"# \u002Fdocumentroot\u002Fwordpress\u002F は仮です。あなたの環境に合わせてください。\n",[98,2920,2921],{"class":100,"line":107},[98,2922,2923],{"class":1050},"# 画像が格納されているuploadsへ移動\n",[98,2925,2926,2929,2932,2935],{"class":100,"line":113},[98,2927,2928],{"class":1120},"cd",[98,2930,2931],{"class":915}," '",[98,2933,2934],{"class":949},"\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads",[98,2936,2937],{"class":915},"'\n",[98,2939,2940],{"class":100,"line":119},[98,2941,2943],{"class":2942},"s5Dmg","ls\n",[98,2945,2946,2949,2952,2955,2958,2961,2964,2967],{"class":100,"line":125},[98,2947,2948],{"class":2942},"2017",[98,2950,2951],{"class":934}," 2018",[98,2953,2954],{"class":934}," 2019",[98,2956,2957],{"class":934}," 2020",[98,2959,2960],{"class":934}," 2021",[98,2962,2963],{"class":949}," aaaa",[98,2965,2966],{"class":949}," bbbbb",[98,2968,2969],{"class":949}," cccc\n",[98,2971,2972],{"class":100,"line":131},[98,2973,389],{"emptyLinePlaceholder":348},[98,2975,2976],{"class":100,"line":137},[98,2977,2978],{"class":1050},"# プラグイン用画像のディレクトリなどもあるので注意！\n",[98,2980,2981],{"class":100,"line":143},[98,2982,2983],{"class":1050},"# 自分がアップロードした画像があるディレクトリのみを指定、500kb以上のものをリストアップ。リストはテキストファイルとしてホームディレクトリにおいておく。\n",[98,2985,2986,2989,2992,2994,2996,2998,3000,3003,3006,3009],{"class":100,"line":149},[98,2987,2988],{"class":2942},"find",[98,2990,2991],{"class":934}," 2017",[98,2993,2951],{"class":934},[98,2995,2954],{"class":934},[98,2997,2957],{"class":934},[98,2999,2960],{"class":934},[98,3001,3002],{"class":949}," -size",[98,3004,3005],{"class":949}," +500k",[98,3007,3008],{"class":915}," >",[98,3010,3011],{"class":949}," ~\u002Flist.txt\n",[98,3013,3014],{"class":100,"line":155},[98,3015,3016],{"class":1120},"..\n",[98,3018,3019],{"class":100,"line":161},[98,3020,3021],{"class":2942},"2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-644x279.png\n",[98,3023,3024],{"class":100,"line":166},[98,3025,3026],{"class":2942},"2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-720x340.png\n",[98,3028,3029],{"class":100,"line":172},[98,3030,3031],{"class":2942},"2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83-768x332.png\n",[98,3033,3034],{"class":100,"line":178},[98,3035,3036],{"class":2942},"2017\u002F12\u002Fd7d6b39a47612239ce48bf6579be7f83.png\n",[98,3038,3039],{"class":100,"line":513},[98,3040,3041],{"class":2942},"2017\u002F12\u002FDSC03961-1200x900.jpg\n",[98,3043,3044],{"class":100,"line":519},[98,3045,3046],{"class":2942},"2017\u002F12\u002FDSC04310-1200x900.jpg\n",[98,3048,3049],{"class":100,"line":525},[98,3050,3051],{"class":2942},"2017\u002F12\u002FDSC04311-1200x900.jpg\n",[98,3053,3054],{"class":100,"line":531},[98,3055,3056],{"class":2942},"2017\u002F12\u002FDSC04314-1200x900.jpg\n",[98,3058,3059],{"class":100,"line":537},[98,3060,3061],{"class":2942},"2017\u002F12\u002FDSC04315-1200x900.jpg\n",[98,3063,3064],{"class":100,"line":543},[98,3065,3066],{"class":2942},"2017\u002F12\u002FDSC04316-1200x900.jpg\n",[98,3068,3069],{"class":100,"line":549},[98,3070,3071],{"class":2942},"2017\u002F12\u002FDSC04317-1200x900.jpg\n",[98,3073,3074],{"class":100,"line":555},[98,3075,3076],{"class":2942},"2017\u002F12\u002FDSC04319-1200x900.jpg\n",[98,3078,3079],{"class":100,"line":561},[98,3080,3081],{"class":2942},"2017\u002F12\u002FDSC04320-e1512559527929-1200x1600.jpg\n",[98,3083,3084],{"class":100,"line":567},[98,3085,3086],{"class":2942},"2017\u002F12\u002FDSC04324-1200x900.jpg\n",[98,3088,3089],{"class":100,"line":573},[98,3090,3091],{"class":2942},"2017\u002F12\u002FDSC04325-1200x900.jpg\n",[98,3093,3094],{"class":100,"line":579},[98,3095,249],{"class":1120},[13,3097,3098,3101,3102,3105],{},[28,3099,3100],{},"find -size "," でファイルサイズでフィルターできます。1000件以上あったりと、コピーするのは大変なので ",[28,3103,3104],{},"list.txt"," などで出力しておきます。",[17,3107,3108],{"id":3108},"画像処理スクリプトを作成",[33,3110,3112],{"id":3111},"リストをphp-arrayにする","リストをPHP Arrayにする",[13,3114,3115,3116,3118],{},"サーバーでのリストアップが終わったので、ローカルでスクリプトを作っていきます。",[28,3117,3104],{}," はローカルに移動しておきます。",[71,3120,3122],{"className":2909,"code":3121,"language":2911,"meta":79,"style":79},".\n├── list.php\n├── image.php\n├── list.txt\n",[28,3123,3124,3129,3137,3144],{"__ignoreMap":79},[98,3125,3126],{"class":100,"line":101},[98,3127,3128],{"class":1120},".\n",[98,3130,3131,3134],{"class":100,"line":107},[98,3132,3133],{"class":2942},"├──",[98,3135,3136],{"class":949}," list.php\n",[98,3138,3139,3141],{"class":100,"line":113},[98,3140,3133],{"class":2942},[98,3142,3143],{"class":949}," image.php\n",[98,3145,3146,3148],{"class":100,"line":119},[98,3147,3133],{"class":2942},[98,3149,3150],{"class":949}," list.txt\n",[13,3152,3153,3155,3156,3159],{},[28,3154,3104],{}," を",[28,3157,3158],{},"list.php"," としてコピーしておき、配列に変換しておきます。テキストエディタの置換機能などを利用してください。",[71,3161,3163],{"className":92,"code":3162,"filename":3158,"language":94,"meta":79,"style":79},"\u003C?php \n$list =[\n\"2017\u002F06\u002F23c7f697593e4a4c83e01310ee4b84ec-1200x900.jpg\",\n\"2017\u002F06\u002F23c7f697593e4a4c83e01310ee4b84ec.jpg\",\n\"2017\u002F06\u002Fcropped-DSC03989-1-1024x723.jpg\",\n\"2017\u002F06\u002Fcropped-DSC03989-1-1200x847.jpg\",\n\"2017\u002F06\u002Fcropped-DSC03989-1.jpg\",\n...\n];\n",[28,3164,3165,3170,3175,3180,3185,3190,3195,3200,3204],{"__ignoreMap":79},[98,3166,3167],{"class":100,"line":101},[98,3168,3169],{},"\u003C?php \n",[98,3171,3172],{"class":100,"line":107},[98,3173,3174],{},"$list =[\n",[98,3176,3177],{"class":100,"line":113},[98,3178,3179],{},"\"2017\u002F06\u002F23c7f697593e4a4c83e01310ee4b84ec-1200x900.jpg\",\n",[98,3181,3182],{"class":100,"line":119},[98,3183,3184],{},"\"2017\u002F06\u002F23c7f697593e4a4c83e01310ee4b84ec.jpg\",\n",[98,3186,3187],{"class":100,"line":125},[98,3188,3189],{},"\"2017\u002F06\u002Fcropped-DSC03989-1-1024x723.jpg\",\n",[98,3191,3192],{"class":100,"line":131},[98,3193,3194],{},"\"2017\u002F06\u002Fcropped-DSC03989-1-1200x847.jpg\",\n",[98,3196,3197],{"class":100,"line":137},[98,3198,3199],{},"\"2017\u002F06\u002Fcropped-DSC03989-1.jpg\",\n",[98,3201,3202],{"class":100,"line":143},[98,3203,249],{},[98,3205,3206],{"class":100,"line":149},[98,3207,3208],{},"];\n",[13,3210,3211,3212,3215],{},"これで対象画像をリストアップして、PHPが扱えるようになったので ",[28,3213,3214],{},"image.php"," にて処理の方を書いていきましょう。",[33,3217,3219],{"id":3218},"画像圧縮リサイズ処理","画像圧縮・リサイズ処理",[3221,3222,3224],"h4",{"id":3223},"そのまえに","そのまえに..",[13,3226,3227,3228,3233],{},"PHPでリサイズなどの画像処理を行う場合は",[196,3229,3232],{"href":3230,"rel":3231},"https:\u002F\u002Fwww.php.net\u002Fmanual\u002Fja\u002Fintro.image.php",[200],"GDというPHPモジュール","を用います。処理を書く前にこのGDモジュールが使用しているPHP環境にあるかを確認しましょう。",[13,3235,3236],{},"phpinfoのページでも確認できますが、手っ取り早くCLIでやりましょう。以下のコマンドを打ちます。",[71,3238,3240],{"className":2909,"code":3239,"language":2911,"meta":79,"style":79},"php --info | grep GD\nGD Support => enabled\nGD headers Version => 2.3.2\nGD library Version => 2.3.2\n",[28,3241,3242,3258,3274,3291],{"__ignoreMap":79},[98,3243,3244,3246,3249,3252,3255],{"class":100,"line":101},[98,3245,94],{"class":2942},[98,3247,3248],{"class":949}," --info",[98,3250,3251],{"class":915}," |",[98,3253,3254],{"class":2942}," grep",[98,3256,3257],{"class":949}," GD\n",[98,3259,3260,3263,3266,3269,3271],{"class":100,"line":107},[98,3261,3262],{"class":2942},"GD",[98,3264,3265],{"class":949}," Support",[98,3267,3268],{"class":911}," =",[98,3270,1258],{"class":915},[98,3272,3273],{"class":949}," enabled\n",[98,3275,3276,3278,3281,3284,3286,3288],{"class":100,"line":113},[98,3277,3262],{"class":2942},[98,3279,3280],{"class":949}," headers",[98,3282,3283],{"class":949}," Version",[98,3285,3268],{"class":911},[98,3287,1258],{"class":915},[98,3289,3290],{"class":934}," 2.3.2\n",[98,3292,3293,3295,3298,3300,3302,3304],{"class":100,"line":119},[98,3294,3262],{"class":2942},[98,3296,3297],{"class":949}," library",[98,3299,3283],{"class":949},[98,3301,3268],{"class":911},[98,3303,1258],{"class":915},[98,3305,3290],{"class":934},[13,3307,3308,3311],{},[28,3309,3310],{},"GD Support => enabled"," が存在し、enabledとなっていれば使用可能です。ない場合などを別途インストールが必要です。まあwordpressが使用できる環境ならば大抵入っていると思います。これでGDの確認を行ったら、処理を書きます。",[3221,3313,3314],{"id":3314},"処理の記述",[13,3316,3317],{},"今回のスクリプトはCMSがるサーバー上で実行するものとします。そのためパスなどの構成も予め、サーバー上であることを想定してます。",[13,3319,3320],{},"全体は以下の通りです。",[71,3322,3324],{"className":92,"code":3323,"language":94,"meta":79,"style":79},"\u003C?php \n    require_once 'list.php';\n\n    $uploadRoot = '\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads\u002F';\n\n    foreach($list as $file){\n        \u002F** \n         * ファイル名などを分けておく。\n         * \n         * 例\n         * $file            => '2017\u002F12\u002FDSC04325-1200x900.jpg'\n         * $targetFilename  => 'DSC04325-1200x900.jpg'\n         * $fullPath        => '\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads\u002F2017\u002F12\u002FDSC04325-1200x900.jpg'\n        *\u002F\n        $filenames = explode('\u002F',$file);\n        $targetFilename = $filenames[count($filenames)-1];\n        $fullPath = $uploadRoot.$file;\n\n        \u002F\u002F getimagesize()を用いて寸法、拡張子の情報を取得。\n        list($w, $h,$type) = getimagesize($fullPath);\n        var_dump($fullPath);\n\n        \u002F\u002F imagecreatefromjpeg()・imagecreatefrompng()にてGDImageを取得。画像を取得しているんだなぐらいだと思ってください。\n        \u002F\u002F JPG\u002FPNGによって分ける必要あり！。\n        switch ($type) {\n            case IMAGETYPE_JPEG:\n                $original_image = imagecreatefromjpeg($fullPath);\n                break;\n            case IMAGETYPE_PNG:\n                $original_image = imagecreatefrompng($fullPath);\n                break;\n            default:\n                var_dump('対応していないファイル形式です。: '.$fullPath);\n                continue;\n        }\n\n        \u002F\u002F 寸法が大きすぎるもの(1000px以上)は600pxぐにらいするリサイズ処理を行う。\n        if($w >= 1000){\n\n            \u002F\u002F imagecreatetruecolor() で新しい画像を埋め込むための「枠」を作る。（新しいキャンバス的な？）\n            \u002F\u002F 縦横比を計算させて元画像と同じにさせること。\n            $newW = 600;\n            $newH = $newW * ($h \u002F $w);\n            $newImg = imagecreatetruecolor($newW, $newH);\n\n            \u002F\u002F リサイズ処理。\n            $success = imagecopyresampled($newImg, $original_image, 0, 0, 0, 0, $newW, $newH, $w, $h);\n\n            if($success){\n                $original_image = $newImg;\n            }else{\n                var_dump('リサイズ失敗: '.$fullPath);\n                continue;\n            }\n        }\n\n        \u002F\u002F 画像を圧縮して同じ名前、パスで上書き保存する。ここも拡張子で異なるので注意！\n        \u002F\u002F 数字は圧縮の品質。低いほど軽くなるが、粗くなる。jpgは0~100,pngは0~9なので注意。\n        switch ($type) {\n            case IMAGETYPE_JPEG:\n                imagejpeg($original_image,$fullPath,60);\n                break;\n            case IMAGETYPE_PNG:\n                imagepng($original_image,$fullPath,6);\n                break;\n            default:\n                var_dump('対応していないファイル形式です。: '.$fullPath);\n                continue;\n        }\n    }\n?>\n",[28,3325,3326,3330,3335,3339,3344,3348,3353,3358,3363,3368,3373,3378,3383,3388,3393,3398,3403,3408,3412,3417,3422,3427,3431,3436,3441,3446,3451,3456,3461,3466,3471,3475,3480,3485,3490,3495,3499,3504,3509,3513,3518,3523,3528,3533,3538,3542,3547,3552,3556,3561,3566,3571,3576,3580,3584,3588,3592,3597,3602,3606,3610,3615,3619,3623,3628,3632,3636,3641,3646,3651,3657],{"__ignoreMap":79},[98,3327,3328],{"class":100,"line":101},[98,3329,3169],{},[98,3331,3332],{"class":100,"line":107},[98,3333,3334],{},"    require_once 'list.php';\n",[98,3336,3337],{"class":100,"line":113},[98,3338,389],{"emptyLinePlaceholder":348},[98,3340,3341],{"class":100,"line":119},[98,3342,3343],{},"    $uploadRoot = '\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads\u002F';\n",[98,3345,3346],{"class":100,"line":125},[98,3347,389],{"emptyLinePlaceholder":348},[98,3349,3350],{"class":100,"line":131},[98,3351,3352],{},"    foreach($list as $file){\n",[98,3354,3355],{"class":100,"line":137},[98,3356,3357],{},"        \u002F** \n",[98,3359,3360],{"class":100,"line":143},[98,3361,3362],{},"         * ファイル名などを分けておく。\n",[98,3364,3365],{"class":100,"line":149},[98,3366,3367],{},"         * \n",[98,3369,3370],{"class":100,"line":155},[98,3371,3372],{},"         * 例\n",[98,3374,3375],{"class":100,"line":161},[98,3376,3377],{},"         * $file            => '2017\u002F12\u002FDSC04325-1200x900.jpg'\n",[98,3379,3380],{"class":100,"line":166},[98,3381,3382],{},"         * $targetFilename  => 'DSC04325-1200x900.jpg'\n",[98,3384,3385],{"class":100,"line":172},[98,3386,3387],{},"         * $fullPath        => '\u002Fdocumentroot\u002Fwordpress\u002Fwp-content\u002Fuploads\u002F2017\u002F12\u002FDSC04325-1200x900.jpg'\n",[98,3389,3390],{"class":100,"line":178},[98,3391,3392],{},"        *\u002F\n",[98,3394,3395],{"class":100,"line":513},[98,3396,3397],{},"        $filenames = explode('\u002F',$file);\n",[98,3399,3400],{"class":100,"line":519},[98,3401,3402],{},"        $targetFilename = $filenames[count($filenames)-1];\n",[98,3404,3405],{"class":100,"line":525},[98,3406,3407],{},"        $fullPath = $uploadRoot.$file;\n",[98,3409,3410],{"class":100,"line":531},[98,3411,389],{"emptyLinePlaceholder":348},[98,3413,3414],{"class":100,"line":537},[98,3415,3416],{},"        \u002F\u002F getimagesize()を用いて寸法、拡張子の情報を取得。\n",[98,3418,3419],{"class":100,"line":543},[98,3420,3421],{},"        list($w, $h,$type) = getimagesize($fullPath);\n",[98,3423,3424],{"class":100,"line":549},[98,3425,3426],{},"        var_dump($fullPath);\n",[98,3428,3429],{"class":100,"line":555},[98,3430,389],{"emptyLinePlaceholder":348},[98,3432,3433],{"class":100,"line":561},[98,3434,3435],{},"        \u002F\u002F imagecreatefromjpeg()・imagecreatefrompng()にてGDImageを取得。画像を取得しているんだなぐらいだと思ってください。\n",[98,3437,3438],{"class":100,"line":567},[98,3439,3440],{},"        \u002F\u002F JPG\u002FPNGによって分ける必要あり！。\n",[98,3442,3443],{"class":100,"line":573},[98,3444,3445],{},"        switch ($type) {\n",[98,3447,3448],{"class":100,"line":579},[98,3449,3450],{},"            case IMAGETYPE_JPEG:\n",[98,3452,3453],{"class":100,"line":585},[98,3454,3455],{},"                $original_image = imagecreatefromjpeg($fullPath);\n",[98,3457,3458],{"class":100,"line":591},[98,3459,3460],{},"                break;\n",[98,3462,3463],{"class":100,"line":4},[98,3464,3465],{},"            case IMAGETYPE_PNG:\n",[98,3467,3468],{"class":100,"line":602},[98,3469,3470],{},"                $original_image = imagecreatefrompng($fullPath);\n",[98,3472,3473],{"class":100,"line":608},[98,3474,3460],{},[98,3476,3477],{"class":100,"line":614},[98,3478,3479],{},"            default:\n",[98,3481,3482],{"class":100,"line":620},[98,3483,3484],{},"                var_dump('対応していないファイル形式です。: '.$fullPath);\n",[98,3486,3487],{"class":100,"line":626},[98,3488,3489],{},"                continue;\n",[98,3491,3492],{"class":100,"line":632},[98,3493,3494],{},"        }\n",[98,3496,3497],{"class":100,"line":638},[98,3498,389],{"emptyLinePlaceholder":348},[98,3500,3501],{"class":100,"line":643},[98,3502,3503],{},"        \u002F\u002F 寸法が大きすぎるもの(1000px以上)は600pxぐにらいするリサイズ処理を行う。\n",[98,3505,3506],{"class":100,"line":649},[98,3507,3508],{},"        if($w >= 1000){\n",[98,3510,3511],{"class":100,"line":654},[98,3512,389],{"emptyLinePlaceholder":348},[98,3514,3515],{"class":100,"line":659},[98,3516,3517],{},"            \u002F\u002F imagecreatetruecolor() で新しい画像を埋め込むための「枠」を作る。（新しいキャンバス的な？）\n",[98,3519,3520],{"class":100,"line":664},[98,3521,3522],{},"            \u002F\u002F 縦横比を計算させて元画像と同じにさせること。\n",[98,3524,3525],{"class":100,"line":669},[98,3526,3527],{},"            $newW = 600;\n",[98,3529,3530],{"class":100,"line":674},[98,3531,3532],{},"            $newH = $newW * ($h \u002F $w);\n",[98,3534,3535],{"class":100,"line":679},[98,3536,3537],{},"            $newImg = imagecreatetruecolor($newW, $newH);\n",[98,3539,3540],{"class":100,"line":684},[98,3541,389],{"emptyLinePlaceholder":348},[98,3543,3544],{"class":100,"line":689},[98,3545,3546],{},"            \u002F\u002F リサイズ処理。\n",[98,3548,3549],{"class":100,"line":694},[98,3550,3551],{},"            $success = imagecopyresampled($newImg, $original_image, 0, 0, 0, 0, $newW, $newH, $w, $h);\n",[98,3553,3554],{"class":100,"line":699},[98,3555,389],{"emptyLinePlaceholder":348},[98,3557,3558],{"class":100,"line":704},[98,3559,3560],{},"            if($success){\n",[98,3562,3563],{"class":100,"line":709},[98,3564,3565],{},"                $original_image = $newImg;\n",[98,3567,3568],{"class":100,"line":714},[98,3569,3570],{},"            }else{\n",[98,3572,3573],{"class":100,"line":719},[98,3574,3575],{},"                var_dump('リサイズ失敗: '.$fullPath);\n",[98,3577,3578],{"class":100,"line":724},[98,3579,3489],{},[98,3581,3582],{"class":100,"line":729},[98,3583,2595],{},[98,3585,3586],{"class":100,"line":734},[98,3587,3494],{},[98,3589,3590],{"class":100,"line":739},[98,3591,389],{"emptyLinePlaceholder":348},[98,3593,3594],{"class":100,"line":744},[98,3595,3596],{},"        \u002F\u002F 画像を圧縮して同じ名前、パスで上書き保存する。ここも拡張子で異なるので注意！\n",[98,3598,3599],{"class":100,"line":749},[98,3600,3601],{},"        \u002F\u002F 数字は圧縮の品質。低いほど軽くなるが、粗くなる。jpgは0~100,pngは0~9なので注意。\n",[98,3603,3604],{"class":100,"line":754},[98,3605,3445],{},[98,3607,3608],{"class":100,"line":759},[98,3609,3450],{},[98,3611,3612],{"class":100,"line":764},[98,3613,3614],{},"                imagejpeg($original_image,$fullPath,60);\n",[98,3616,3617],{"class":100,"line":769},[98,3618,3460],{},[98,3620,3621],{"class":100,"line":774},[98,3622,3465],{},[98,3624,3625],{"class":100,"line":779},[98,3626,3627],{},"                imagepng($original_image,$fullPath,6);\n",[98,3629,3630],{"class":100,"line":785},[98,3631,3460],{},[98,3633,3634],{"class":100,"line":791},[98,3635,3479],{},[98,3637,3639],{"class":100,"line":3638},67,[98,3640,3484],{},[98,3642,3644],{"class":100,"line":3643},68,[98,3645,3489],{},[98,3647,3649],{"class":100,"line":3648},69,[98,3650,3494],{},[98,3652,3654],{"class":100,"line":3653},70,[98,3655,3656],{},"    }\n",[98,3658,3660],{"class":100,"line":3659},71,[98,3661,3662],{},"?>\n",[13,3664,3665,3666,3669],{},"書いてあるコメントの通りです。ただGDは拡張子ごとに使用する関数を分ける必要があるので、そこがめんどいです。listで予めどんな拡張子が使用されているかを確かめておきましょう。ローカルでテストを行ったら、",[28,3667,3668],{},"image.php, list.php","をサーバーに転送します。",[17,3671,3673],{"id":3672},"実行前の注意","実行前の注意！",[13,3675,3676,3677,3680],{},"実行する前に必ず ",[28,3678,3679],{},"uploads"," のバックアップをしておきましょう。そうすればもしやらかしたり、予想以上に粗くなったとしてもやり直しができます。OKであれば",[71,3682,3685],{"className":3683,"code":3684,"language":76},[74],"php image.php\n",[28,3686,3684],{"__ignoreMap":79},[13,3688,3689],{},"そして実行しましょう。私の場合1500画像で5分ほどで終わった気がします。",[13,3691,3692,3695],{},[28,3693,3694],{},"ls -lh"," や上記のfindコマンドで重い画像がなくなったかを確認しましょう。また、画像のパスをブラウザで叩いて確認してもいいかもしれません。キャッシュが効いていることが多いので、シークレットモードで見ることをお勧めします。",[328,3697,3698],{},"html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}",{"title":79,"searchDepth":113,"depth":113,"links":3700},[3701,3702,3703,3710],{"id":2874,"depth":107,"text":2874},{"id":2903,"depth":107,"text":2903},{"id":3108,"depth":107,"text":3108,"children":3704},[3705,3706],{"id":3111,"depth":113,"text":3112},{"id":3218,"depth":113,"text":3219,"children":3707},[3708,3709],{"id":3223,"depth":119,"text":3224},{"id":3314,"depth":119,"text":3314},{"id":3672,"depth":107,"text":3673},[342],"2021-08-15","wordpressに保存された1〜4MBの1500件の画像を一括に処理する。",{},"\u002Farticles\u002Fwp-batch-image-compress",{"title":2860,"description":3713},"articles\u002Fwp-batch-image-compress",[3719,94],"wordpress","XoVocS1wgJ1s3OqIpny9hQofVYNRjvOcumKbgZx2d98",{"id":3722,"title":3723,"body":3724,"category":5379,"createdAt":5380,"description":5381,"extension":345,"index":346,"meta":5382,"navigation":348,"path":5383,"publish":348,"seo":5384,"series":346,"seriesTitle":346,"stem":5385,"tag":5386,"thumbnail":5387,"updatedAt":346,"__hash__":5388},"articles\u002Farticles\u002Fuseful-sass-mixins.md","Sassをプロジェクトで使うときに役に立つメディアクエリmixinとカラーパターン",{"type":10,"value":3725,"toc":5375},[3726,3729,3740,3743,3746,3749,3752,3833,3836,4582,4585,4693,4708,4711,4726,4877,4880,5046,5049,5362,5365,5369,5372],[13,3727,3728],{},"こんにちはjunです。最近のプロジェクトではsassばかり使っていてもうcssを書くことがなくなっているせいか、sassの記法でcssを書いてしまいエラーを起こすことも何回かありました笑。sassはフロントエンドで開発するならば絶対に使えておきたいツールです。その中でプロジェクトに関係なく、同じユーティリティーなライブラリ的なmixinを使うことがあります。",[13,3730,3731,3732,3735,3736,3739],{},"例えば引数を指定するだけでプロジェクトで定義したメディアクエリを出すmixin、bootstrapのように",[28,3733,3734],{},"component-primary","とすれば",[28,3737,3738],{},"primary","色にしてくれるクラスを出力するmixinなどです。mixin意外にもmargin,paddingのユーティリティなどもよく使います。",[13,3741,3742],{},"いつも忘れてサイトを探して時間を潰しているのでここにメモしたいと思います。",[13,3744,3745],{},"※sassの解説ですがscssの記述をします！sass=scssと思ってみてください。",[17,3747,3748],{"id":3748},"引数を使用して特定のメディアクエリを利かすmixin",[13,3750,3751],{},"sassを使用する場合、あるクラスに対するメディアクエリは以下のように付与できます。",[71,3753,3757],{"className":3754,"code":3755,"language":3756,"meta":79,"style":79},"language-scss shiki shiki-themes material-theme-ocean",".p-project{\n    font-size:20px;\n\n    @media screen and (max-width: 399px){\n        font-size:10px;\n    } \n}\n","scss",[28,3758,3759,3768,3781,3785,3810,3822,3829],{"__ignoreMap":79},[98,3760,3761,3763,3766],{"class":100,"line":101},[98,3762,1100],{"class":915},[98,3764,3765],{"class":2942},"p-project",[98,3767,140],{"class":915},[98,3769,3770,3774,3776,3779],{"class":100,"line":107},[98,3771,3773],{"class":3772},"s6YsC","    font-size",[98,3775,931],{"class":915},[98,3777,3778],{"class":934},"20px",[98,3780,1106],{"class":915},[98,3782,3783],{"class":100,"line":113},[98,3784,389],{"emptyLinePlaceholder":348},[98,3786,3787,3790,3793,3796,3799,3802,3804,3807],{"class":100,"line":119},[98,3788,3789],{"class":1852},"    @media",[98,3791,3792],{"class":911}," screen ",[98,3794,3795],{"class":915},"and",[98,3797,3798],{"class":915}," (",[98,3800,3801],{"class":2942},"max-width",[98,3803,931],{"class":915},[98,3805,3806],{"class":934}," 399px",[98,3808,3809],{"class":915},"){\n",[98,3811,3812,3815,3817,3820],{"class":100,"line":125},[98,3813,3814],{"class":3772},"        font-size",[98,3816,931],{"class":915},[98,3818,3819],{"class":934},"10px",[98,3821,1106],{"class":915},[98,3823,3824,3826],{"class":100,"line":131},[98,3825,2817],{"class":915},[98,3827,3828],{"class":911}," \n",[98,3830,3831],{"class":100,"line":137},[98,3832,181],{"class":915},[13,3834,3835],{},"cssの場合はメディアクエリでクラスを囲む必要ありますが、sassは対象のクラスでラップするだけで有効なのでかなり便利です。ただしメディアクエリの記述が長いこと、ブレークポイントの数値・変数を入れるのが面倒なので以下のようなmixinを作成します。",[71,3837,3839],{"className":3754,"code":3838,"language":3756,"meta":79,"style":79},"$sm-point:400;\n$md-point:600;\n$lg-point:1000;\n$xl-point:1300;\n\n$breakpoint-up: (\n  'sm': 'screen and (min-width: #{$sm-point}px)',\n  'md': 'screen and (min-width: #{$md-point}px)',\n  'lg': 'screen and (min-width: #{$lg-point}px)',\n  'xl': 'screen and (min-width: #{$xl-point}px)',\n) !default;\n\n$breakpoint-down: (\n  'sm': 'screen and (max-width: #{$sm-point - 1}px)',\n  'md': 'screen and (max-width: #{$md-point - 1}px)',\n  'lg': 'screen and (max-width: #{$lg-point - 1}px)',\n  'xl': 'screen and (max-width: #{$xl-point - 1}px)',\n) !default;\n\n$breakpoint-only: (\n  'sm': 'screen and (max-width: #{$sm-point - 1}px)',\n  'md-sm': 'screen and (max-width: #{$md-point - 1}px) and (min-width: #{$sm-point}px)',\n  'lg-md': 'screen and (max-width: #{$lg-point - 1}px) and (min-width: #{$md-point}px)',\n  'xl-lg': 'screen and (max-width: #{$xl-point - 1}px) and (min-width: #{$lg-point}px)',\n  'xl': 'screen and (min-width: #{$xl-point}px)',\n) !default;\n\n\u002F*\nsm  =>  スマホ\nmd  =>  タブレット\nlg  =>  PC\nxl  =>  でかいPC\n*\u002F\n\n@mixin mq-up($breakpoint: md) {\n  @media #{map-get($breakpoint-up, $breakpoint)} {\n    @content;\n  }\n}\n\n@mixin mq-down($breakpoint: md) {\n  @media #{map-get($breakpoint-down, $breakpoint)} {\n    @content;\n  }\n}\n\n@mixin mq-only($breakpoint: md-sm) {\n  @media #{map-get($breakpoint-only, $breakpoint)} {\n    @content;\n  }\n}\n",[28,3840,3841,3853,3865,3877,3889,3893,3903,3935,3961,3988,4015,4024,4028,4037,4071,4102,4133,4164,4172,4176,4185,4215,4255,4294,4333,4359,4367,4371,4376,4381,4386,4391,4396,4400,4404,4426,4451,4458,4463,4467,4471,4490,4510,4516,4520,4524,4528,4548,4568,4574,4578],{"__ignoreMap":79},[98,3842,3843,3846,3848,3851],{"class":100,"line":101},[98,3844,3845],{"class":911},"$sm-point",[98,3847,931],{"class":915},[98,3849,3850],{"class":934},"400",[98,3852,1106],{"class":915},[98,3854,3855,3858,3860,3863],{"class":100,"line":107},[98,3856,3857],{"class":911},"$md-point",[98,3859,931],{"class":915},[98,3861,3862],{"class":934},"600",[98,3864,1106],{"class":915},[98,3866,3867,3870,3872,3875],{"class":100,"line":113},[98,3868,3869],{"class":911},"$lg-point",[98,3871,931],{"class":915},[98,3873,3874],{"class":934},"1000",[98,3876,1106],{"class":915},[98,3878,3879,3882,3884,3887],{"class":100,"line":119},[98,3880,3881],{"class":911},"$xl-point",[98,3883,931],{"class":915},[98,3885,3886],{"class":934},"1300",[98,3888,1106],{"class":915},[98,3890,3891],{"class":100,"line":125},[98,3892,389],{"emptyLinePlaceholder":348},[98,3894,3895,3898,3900],{"class":100,"line":131},[98,3896,3897],{"class":911},"$breakpoint-up",[98,3899,931],{"class":915},[98,3901,3902],{"class":915}," (\n",[98,3904,3905,3908,3911,3913,3916,3918,3921,3924,3926,3928,3931,3933],{"class":100,"line":137},[98,3906,3907],{"class":915},"  '",[98,3909,3910],{"class":949},"sm",[98,3912,2738],{"class":915},[98,3914,3915],{"class":911},": ",[98,3917,2738],{"class":915},[98,3919,3920],{"class":949},"screen and (min-width: ",[98,3922,3923],{"class":915},"#{",[98,3925,3845],{"class":911},[98,3927,1316],{"class":915},[98,3929,3930],{"class":949},"px)",[98,3932,2738],{"class":915},[98,3934,2493],{"class":915},[98,3936,3937,3939,3941,3943,3945,3947,3949,3951,3953,3955,3957,3959],{"class":100,"line":143},[98,3938,3907],{"class":915},[98,3940,345],{"class":949},[98,3942,2738],{"class":915},[98,3944,3915],{"class":911},[98,3946,2738],{"class":915},[98,3948,3920],{"class":949},[98,3950,3923],{"class":915},[98,3952,3857],{"class":911},[98,3954,1316],{"class":915},[98,3956,3930],{"class":949},[98,3958,2738],{"class":915},[98,3960,2493],{"class":915},[98,3962,3963,3965,3968,3970,3972,3974,3976,3978,3980,3982,3984,3986],{"class":100,"line":149},[98,3964,3907],{"class":915},[98,3966,3967],{"class":949},"lg",[98,3969,2738],{"class":915},[98,3971,3915],{"class":911},[98,3973,2738],{"class":915},[98,3975,3920],{"class":949},[98,3977,3923],{"class":915},[98,3979,3869],{"class":911},[98,3981,1316],{"class":915},[98,3983,3930],{"class":949},[98,3985,2738],{"class":915},[98,3987,2493],{"class":915},[98,3989,3990,3992,3995,3997,3999,4001,4003,4005,4007,4009,4011,4013],{"class":100,"line":155},[98,3991,3907],{"class":915},[98,3993,3994],{"class":949},"xl",[98,3996,2738],{"class":915},[98,3998,3915],{"class":911},[98,4000,2738],{"class":915},[98,4002,3920],{"class":949},[98,4004,3923],{"class":915},[98,4006,3881],{"class":911},[98,4008,1316],{"class":915},[98,4010,3930],{"class":949},[98,4012,2738],{"class":915},[98,4014,2493],{"class":915},[98,4016,4017,4019,4022],{"class":100,"line":161},[98,4018,1864],{"class":915},[98,4020,4021],{"class":934}," !default",[98,4023,1106],{"class":915},[98,4025,4026],{"class":100,"line":166},[98,4027,389],{"emptyLinePlaceholder":348},[98,4029,4030,4033,4035],{"class":100,"line":172},[98,4031,4032],{"class":911},"$breakpoint-down",[98,4034,931],{"class":915},[98,4036,3902],{"class":915},[98,4038,4039,4041,4043,4045,4047,4049,4052,4054,4057,4060,4063,4065,4067,4069],{"class":100,"line":178},[98,4040,3907],{"class":915},[98,4042,3910],{"class":949},[98,4044,2738],{"class":915},[98,4046,3915],{"class":911},[98,4048,2738],{"class":915},[98,4050,4051],{"class":949},"screen and (max-width: ",[98,4053,3923],{"class":915},[98,4055,4056],{"class":911},"$sm-point ",[98,4058,4059],{"class":915},"-",[98,4061,4062],{"class":934}," 1",[98,4064,1316],{"class":915},[98,4066,3930],{"class":949},[98,4068,2738],{"class":915},[98,4070,2493],{"class":915},[98,4072,4073,4075,4077,4079,4081,4083,4085,4087,4090,4092,4094,4096,4098,4100],{"class":100,"line":513},[98,4074,3907],{"class":915},[98,4076,345],{"class":949},[98,4078,2738],{"class":915},[98,4080,3915],{"class":911},[98,4082,2738],{"class":915},[98,4084,4051],{"class":949},[98,4086,3923],{"class":915},[98,4088,4089],{"class":911},"$md-point ",[98,4091,4059],{"class":915},[98,4093,4062],{"class":934},[98,4095,1316],{"class":915},[98,4097,3930],{"class":949},[98,4099,2738],{"class":915},[98,4101,2493],{"class":915},[98,4103,4104,4106,4108,4110,4112,4114,4116,4118,4121,4123,4125,4127,4129,4131],{"class":100,"line":519},[98,4105,3907],{"class":915},[98,4107,3967],{"class":949},[98,4109,2738],{"class":915},[98,4111,3915],{"class":911},[98,4113,2738],{"class":915},[98,4115,4051],{"class":949},[98,4117,3923],{"class":915},[98,4119,4120],{"class":911},"$lg-point ",[98,4122,4059],{"class":915},[98,4124,4062],{"class":934},[98,4126,1316],{"class":915},[98,4128,3930],{"class":949},[98,4130,2738],{"class":915},[98,4132,2493],{"class":915},[98,4134,4135,4137,4139,4141,4143,4145,4147,4149,4152,4154,4156,4158,4160,4162],{"class":100,"line":525},[98,4136,3907],{"class":915},[98,4138,3994],{"class":949},[98,4140,2738],{"class":915},[98,4142,3915],{"class":911},[98,4144,2738],{"class":915},[98,4146,4051],{"class":949},[98,4148,3923],{"class":915},[98,4150,4151],{"class":911},"$xl-point ",[98,4153,4059],{"class":915},[98,4155,4062],{"class":934},[98,4157,1316],{"class":915},[98,4159,3930],{"class":949},[98,4161,2738],{"class":915},[98,4163,2493],{"class":915},[98,4165,4166,4168,4170],{"class":100,"line":531},[98,4167,1864],{"class":915},[98,4169,4021],{"class":934},[98,4171,1106],{"class":915},[98,4173,4174],{"class":100,"line":537},[98,4175,389],{"emptyLinePlaceholder":348},[98,4177,4178,4181,4183],{"class":100,"line":543},[98,4179,4180],{"class":911},"$breakpoint-only",[98,4182,931],{"class":915},[98,4184,3902],{"class":915},[98,4186,4187,4189,4191,4193,4195,4197,4199,4201,4203,4205,4207,4209,4211,4213],{"class":100,"line":549},[98,4188,3907],{"class":915},[98,4190,3910],{"class":949},[98,4192,2738],{"class":915},[98,4194,3915],{"class":911},[98,4196,2738],{"class":915},[98,4198,4051],{"class":949},[98,4200,3923],{"class":915},[98,4202,4056],{"class":911},[98,4204,4059],{"class":915},[98,4206,4062],{"class":934},[98,4208,1316],{"class":915},[98,4210,3930],{"class":949},[98,4212,2738],{"class":915},[98,4214,2493],{"class":915},[98,4216,4217,4219,4222,4224,4226,4228,4230,4232,4234,4236,4238,4240,4243,4245,4247,4249,4251,4253],{"class":100,"line":555},[98,4218,3907],{"class":915},[98,4220,4221],{"class":949},"md-sm",[98,4223,2738],{"class":915},[98,4225,3915],{"class":911},[98,4227,2738],{"class":915},[98,4229,4051],{"class":949},[98,4231,3923],{"class":915},[98,4233,4089],{"class":911},[98,4235,4059],{"class":915},[98,4237,4062],{"class":934},[98,4239,1316],{"class":915},[98,4241,4242],{"class":949},"px) and (min-width: ",[98,4244,3923],{"class":915},[98,4246,3845],{"class":911},[98,4248,1316],{"class":915},[98,4250,3930],{"class":949},[98,4252,2738],{"class":915},[98,4254,2493],{"class":915},[98,4256,4257,4259,4262,4264,4266,4268,4270,4272,4274,4276,4278,4280,4282,4284,4286,4288,4290,4292],{"class":100,"line":561},[98,4258,3907],{"class":915},[98,4260,4261],{"class":949},"lg-md",[98,4263,2738],{"class":915},[98,4265,3915],{"class":911},[98,4267,2738],{"class":915},[98,4269,4051],{"class":949},[98,4271,3923],{"class":915},[98,4273,4120],{"class":911},[98,4275,4059],{"class":915},[98,4277,4062],{"class":934},[98,4279,1316],{"class":915},[98,4281,4242],{"class":949},[98,4283,3923],{"class":915},[98,4285,3857],{"class":911},[98,4287,1316],{"class":915},[98,4289,3930],{"class":949},[98,4291,2738],{"class":915},[98,4293,2493],{"class":915},[98,4295,4296,4298,4301,4303,4305,4307,4309,4311,4313,4315,4317,4319,4321,4323,4325,4327,4329,4331],{"class":100,"line":567},[98,4297,3907],{"class":915},[98,4299,4300],{"class":949},"xl-lg",[98,4302,2738],{"class":915},[98,4304,3915],{"class":911},[98,4306,2738],{"class":915},[98,4308,4051],{"class":949},[98,4310,3923],{"class":915},[98,4312,4151],{"class":911},[98,4314,4059],{"class":915},[98,4316,4062],{"class":934},[98,4318,1316],{"class":915},[98,4320,4242],{"class":949},[98,4322,3923],{"class":915},[98,4324,3869],{"class":911},[98,4326,1316],{"class":915},[98,4328,3930],{"class":949},[98,4330,2738],{"class":915},[98,4332,2493],{"class":915},[98,4334,4335,4337,4339,4341,4343,4345,4347,4349,4351,4353,4355,4357],{"class":100,"line":573},[98,4336,3907],{"class":915},[98,4338,3994],{"class":949},[98,4340,2738],{"class":915},[98,4342,3915],{"class":911},[98,4344,2738],{"class":915},[98,4346,3920],{"class":949},[98,4348,3923],{"class":915},[98,4350,3881],{"class":911},[98,4352,1316],{"class":915},[98,4354,3930],{"class":949},[98,4356,2738],{"class":915},[98,4358,2493],{"class":915},[98,4360,4361,4363,4365],{"class":100,"line":579},[98,4362,1864],{"class":915},[98,4364,4021],{"class":934},[98,4366,1106],{"class":915},[98,4368,4369],{"class":100,"line":585},[98,4370,389],{"emptyLinePlaceholder":348},[98,4372,4373],{"class":100,"line":591},[98,4374,4375],{"class":1050},"\u002F*\n",[98,4377,4378],{"class":100,"line":4},[98,4379,4380],{"class":1050},"sm  =>  スマホ\n",[98,4382,4383],{"class":100,"line":602},[98,4384,4385],{"class":1050},"md  =>  タブレット\n",[98,4387,4388],{"class":100,"line":608},[98,4389,4390],{"class":1050},"lg  =>  PC\n",[98,4392,4393],{"class":100,"line":614},[98,4394,4395],{"class":1050},"xl  =>  でかいPC\n",[98,4397,4398],{"class":100,"line":620},[98,4399,128],{"class":1050},[98,4401,4402],{"class":100,"line":626},[98,4403,389],{"emptyLinePlaceholder":348},[98,4405,4406,4409,4412,4414,4417,4419,4422,4424],{"class":100,"line":632},[98,4407,4408],{"class":1852},"@mixin",[98,4410,4411],{"class":1120}," mq-up",[98,4413,1839],{"class":915},[98,4415,4416],{"class":911},"$breakpoint",[98,4418,931],{"class":915},[98,4420,4421],{"class":911}," md",[98,4423,1864],{"class":915},[98,4425,2448],{"class":915},[98,4427,4428,4431,4434,4437,4439,4441,4443,4446,4449],{"class":100,"line":638},[98,4429,4430],{"class":1852},"  @media",[98,4432,4433],{"class":915}," #{",[98,4435,4436],{"class":1120},"map-get",[98,4438,1839],{"class":915},[98,4440,3897],{"class":911},[98,4442,938],{"class":915},[98,4444,4445],{"class":911}," $breakpoint",[98,4447,4448],{"class":915},")}",[98,4450,2448],{"class":915},[98,4452,4453,4456],{"class":100,"line":643},[98,4454,4455],{"class":1852},"    @content",[98,4457,1106],{"class":915},[98,4459,4460],{"class":100,"line":649},[98,4461,4462],{"class":915},"  }\n",[98,4464,4465],{"class":100,"line":654},[98,4466,181],{"class":915},[98,4468,4469],{"class":100,"line":659},[98,4470,389],{"emptyLinePlaceholder":348},[98,4472,4473,4475,4478,4480,4482,4484,4486,4488],{"class":100,"line":664},[98,4474,4408],{"class":1852},[98,4476,4477],{"class":1120}," mq-down",[98,4479,1839],{"class":915},[98,4481,4416],{"class":911},[98,4483,931],{"class":915},[98,4485,4421],{"class":911},[98,4487,1864],{"class":915},[98,4489,2448],{"class":915},[98,4491,4492,4494,4496,4498,4500,4502,4504,4506,4508],{"class":100,"line":669},[98,4493,4430],{"class":1852},[98,4495,4433],{"class":915},[98,4497,4436],{"class":1120},[98,4499,1839],{"class":915},[98,4501,4032],{"class":911},[98,4503,938],{"class":915},[98,4505,4445],{"class":911},[98,4507,4448],{"class":915},[98,4509,2448],{"class":915},[98,4511,4512,4514],{"class":100,"line":674},[98,4513,4455],{"class":1852},[98,4515,1106],{"class":915},[98,4517,4518],{"class":100,"line":679},[98,4519,4462],{"class":915},[98,4521,4522],{"class":100,"line":684},[98,4523,181],{"class":915},[98,4525,4526],{"class":100,"line":689},[98,4527,389],{"emptyLinePlaceholder":348},[98,4529,4530,4532,4535,4537,4539,4541,4544,4546],{"class":100,"line":694},[98,4531,4408],{"class":1852},[98,4533,4534],{"class":1120}," mq-only",[98,4536,1839],{"class":915},[98,4538,4416],{"class":911},[98,4540,931],{"class":915},[98,4542,4543],{"class":911}," md-sm",[98,4545,1864],{"class":915},[98,4547,2448],{"class":915},[98,4549,4550,4552,4554,4556,4558,4560,4562,4564,4566],{"class":100,"line":699},[98,4551,4430],{"class":1852},[98,4553,4433],{"class":915},[98,4555,4436],{"class":1120},[98,4557,1839],{"class":915},[98,4559,4180],{"class":911},[98,4561,938],{"class":915},[98,4563,4445],{"class":911},[98,4565,4448],{"class":915},[98,4567,2448],{"class":915},[98,4569,4570,4572],{"class":100,"line":704},[98,4571,4455],{"class":1852},[98,4573,1106],{"class":915},[98,4575,4576],{"class":100,"line":709},[98,4577,4462],{"class":915},[98,4579,4580],{"class":100,"line":714},[98,4581,181],{"class":915},[13,4583,4584],{},"実際に使用する際は以下のようにします。",[71,4586,4588],{"className":3754,"code":4587,"language":3756,"meta":79,"style":79},".test{\n    @include mq-up(xl){\n        \u002F\u002F 1300px以上で有効\n        background-color:blue;\n    }\n\n    @include mq-only(md-sm){\n        \u002F\u002F 599px〜400pxで有効\n        background-color:yellow;\n    }\n\n    \u002F\u002F 1299px ~ 600px, 399px~ で有効\n    background-color:red;\n}\n",[28,4589,4590,4598,4611,4616,4628,4632,4636,4648,4653,4664,4668,4672,4677,4689],{"__ignoreMap":79},[98,4591,4592,4594,4596],{"class":100,"line":101},[98,4593,1100],{"class":915},[98,4595,2715],{"class":2942},[98,4597,140],{"class":915},[98,4599,4600,4603,4605,4607,4609],{"class":100,"line":107},[98,4601,4602],{"class":1852},"    @include",[98,4604,4411],{"class":1120},[98,4606,1839],{"class":915},[98,4608,3994],{"class":911},[98,4610,3809],{"class":915},[98,4612,4613],{"class":100,"line":113},[98,4614,4615],{"class":1050},"        \u002F\u002F 1300px以上で有効\n",[98,4617,4618,4621,4623,4626],{"class":100,"line":119},[98,4619,4620],{"class":3772},"        background-color",[98,4622,931],{"class":915},[98,4624,4625],{"class":911},"blue",[98,4627,1106],{"class":915},[98,4629,4630],{"class":100,"line":125},[98,4631,3656],{"class":915},[98,4633,4634],{"class":100,"line":131},[98,4635,389],{"emptyLinePlaceholder":348},[98,4637,4638,4640,4642,4644,4646],{"class":100,"line":137},[98,4639,4602],{"class":1852},[98,4641,4534],{"class":1120},[98,4643,1839],{"class":915},[98,4645,4221],{"class":911},[98,4647,3809],{"class":915},[98,4649,4650],{"class":100,"line":143},[98,4651,4652],{"class":1050},"        \u002F\u002F 599px〜400pxで有効\n",[98,4654,4655,4657,4659,4662],{"class":100,"line":149},[98,4656,4620],{"class":3772},[98,4658,931],{"class":915},[98,4660,4661],{"class":911},"yellow",[98,4663,1106],{"class":915},[98,4665,4666],{"class":100,"line":155},[98,4667,3656],{"class":915},[98,4669,4670],{"class":100,"line":161},[98,4671,389],{"emptyLinePlaceholder":348},[98,4673,4674],{"class":100,"line":166},[98,4675,4676],{"class":1050},"    \u002F\u002F 1299px ~ 600px, 399px~ で有効\n",[98,4678,4679,4682,4684,4687],{"class":100,"line":172},[98,4680,4681],{"class":3772},"    background-color",[98,4683,931],{"class":915},[98,4685,4686],{"class":911},"red",[98,4688,1106],{"class":915},[98,4690,4691],{"class":100,"line":178},[98,4692,181],{"class":915},[13,4694,4695,4696,4699,4700,4703,4704,4707],{},"このようにメディアクエリをかなり短く記述できます。引数を指定するだけなので直感的ですし、変数でサイズを定義しているので変更もしやすいです。",[28,4697,4698],{},"mq-up","、",[28,4701,4702],{},"mq-down","はあるブレークポイント以上・以下で働くメディアクエリですが、",[28,4705,4706],{},"mq-only","は指定したメディアクエリ間のみ作用します。このメディアクエリmixinはかなり役に立ち、プロジェクトセットアップ時に毎回やっています。",[17,4709,4710],{"id":4710},"カラーパターンクラス",[13,4712,4713,4714,4717,4718,4721,4722,4725],{},"Bootstrapのボタンクラスで",[28,4715,4716],{},"btn btn-danger","とすると赤い色のボタンになります。",[28,4719,4720],{},"warning","なら黄色、",[28,4723,4724],{},"danger","なら赤色といった具合に色の設定をして、その色のクラスがあればその色にするクラスを作成するmixinです。まずは色をmapで定義します。",[71,4727,4729],{"className":3754,"code":4728,"language":3756,"meta":79,"style":79},"$colors:(\n    \"red\"   :#E60012,\n    \"orange\":#F39800,\n    \"yellow\":#FFF100,\n    \"green\" :#009944,\n    \"blue\"  :#0068B7,\n    \"purple\":#920783,\n);\n$default-color:map-get($colors,\"red\");\n",[28,4730,4731,4739,4759,4777,4794,4813,4831,4849,4854],{"__ignoreMap":79},[98,4732,4733,4736],{"class":100,"line":101},[98,4734,4735],{"class":911},"$colors",[98,4737,4738],{"class":915},":(\n",[98,4740,4741,4744,4746,4748,4751,4754,4757],{"class":100,"line":107},[98,4742,4743],{"class":915},"    \"",[98,4745,4686],{"class":949},[98,4747,946],{"class":915},[98,4749,4750],{"class":911},"   :",[98,4752,4753],{"class":915},"#",[98,4755,4756],{"class":911},"E60012",[98,4758,2493],{"class":915},[98,4760,4761,4763,4766,4768,4770,4772,4775],{"class":100,"line":113},[98,4762,4743],{"class":915},[98,4764,4765],{"class":949},"orange",[98,4767,946],{"class":915},[98,4769,931],{"class":911},[98,4771,4753],{"class":915},[98,4773,4774],{"class":911},"F39800",[98,4776,2493],{"class":915},[98,4778,4779,4781,4783,4785,4787,4789,4792],{"class":100,"line":119},[98,4780,4743],{"class":915},[98,4782,4661],{"class":949},[98,4784,946],{"class":915},[98,4786,931],{"class":911},[98,4788,4753],{"class":915},[98,4790,4791],{"class":911},"FFF100",[98,4793,2493],{"class":915},[98,4795,4796,4798,4801,4803,4806,4808,4811],{"class":100,"line":125},[98,4797,4743],{"class":915},[98,4799,4800],{"class":949},"green",[98,4802,946],{"class":915},[98,4804,4805],{"class":911}," :",[98,4807,4753],{"class":915},[98,4809,4810],{"class":911},"009944",[98,4812,2493],{"class":915},[98,4814,4815,4817,4819,4821,4824,4826,4829],{"class":100,"line":131},[98,4816,4743],{"class":915},[98,4818,4625],{"class":949},[98,4820,946],{"class":915},[98,4822,4823],{"class":911},"  :",[98,4825,4753],{"class":915},[98,4827,4828],{"class":911},"0068B7",[98,4830,2493],{"class":915},[98,4832,4833,4835,4838,4840,4842,4844,4847],{"class":100,"line":137},[98,4834,4743],{"class":915},[98,4836,4837],{"class":949},"purple",[98,4839,946],{"class":915},[98,4841,931],{"class":911},[98,4843,4753],{"class":915},[98,4845,4846],{"class":911},"920783",[98,4848,2493],{"class":915},[98,4850,4851],{"class":100,"line":143},[98,4852,4853],{"class":915},");\n",[98,4855,4856,4859,4861,4863,4865,4867,4869,4871,4873,4875],{"class":100,"line":149},[98,4857,4858],{"class":911},"$default-color",[98,4860,931],{"class":915},[98,4862,4436],{"class":1120},[98,4864,1839],{"class":915},[98,4866,4735],{"class":911},[98,4868,938],{"class":915},[98,4870,946],{"class":915},[98,4872,4686],{"class":949},[98,4874,946],{"class":915},[98,4876,4853],{"class":915},[13,4878,4879],{},"そしてボタンのクラスがあるとします。",[71,4881,4883],{"className":3754,"code":4882,"language":3756,"meta":79,"style":79},".btn{\n    background-color:$default-color;\n    border:1px solid;\n    border-color:darken($default-color,15%);\n    border-radius:5px;\n    padding:10px;\n    text-align:center;\n\n    @each $key, $color in $colors {\n        &-#{$key}{\n            background-color:$color;\n            border-color:darken($color,15%);\n        }\n    }\n}\n",[28,4884,4885,4894,4904,4919,4940,4952,4963,4975,4979,4995,5003,5015,5034,5038,5042],{"__ignoreMap":79},[98,4886,4887,4889,4892],{"class":100,"line":101},[98,4888,1100],{"class":915},[98,4890,4891],{"class":2942},"btn",[98,4893,140],{"class":915},[98,4895,4896,4898,4900,4902],{"class":100,"line":107},[98,4897,4681],{"class":3772},[98,4899,931],{"class":915},[98,4901,4858],{"class":911},[98,4903,1106],{"class":915},[98,4905,4906,4909,4911,4914,4917],{"class":100,"line":113},[98,4907,4908],{"class":3772},"    border",[98,4910,931],{"class":915},[98,4912,4913],{"class":934},"1px",[98,4915,4916],{"class":911}," solid",[98,4918,1106],{"class":915},[98,4920,4921,4924,4926,4929,4931,4933,4935,4938],{"class":100,"line":119},[98,4922,4923],{"class":3772},"    border-color",[98,4925,931],{"class":915},[98,4927,4928],{"class":1120},"darken",[98,4930,1839],{"class":915},[98,4932,4858],{"class":911},[98,4934,938],{"class":915},[98,4936,4937],{"class":934},"15%",[98,4939,4853],{"class":915},[98,4941,4942,4945,4947,4950],{"class":100,"line":125},[98,4943,4944],{"class":3772},"    border-radius",[98,4946,931],{"class":915},[98,4948,4949],{"class":934},"5px",[98,4951,1106],{"class":915},[98,4953,4954,4957,4959,4961],{"class":100,"line":131},[98,4955,4956],{"class":3772},"    padding",[98,4958,931],{"class":915},[98,4960,3819],{"class":934},[98,4962,1106],{"class":915},[98,4964,4965,4968,4970,4973],{"class":100,"line":137},[98,4966,4967],{"class":3772},"    text-align",[98,4969,931],{"class":915},[98,4971,4972],{"class":911},"center",[98,4974,1106],{"class":915},[98,4976,4977],{"class":100,"line":143},[98,4978,389],{"emptyLinePlaceholder":348},[98,4980,4981,4984,4987,4990,4993],{"class":100,"line":149},[98,4982,4983],{"class":1852},"    @each",[98,4985,4986],{"class":911}," $key, $color ",[98,4988,4989],{"class":1852},"in",[98,4991,4992],{"class":911}," $colors ",[98,4994,140],{"class":915},[98,4996,4997,5000],{"class":100,"line":155},[98,4998,4999],{"class":2942},"        &",[98,5001,5002],{"class":915},"-#{$key}{\n",[98,5004,5005,5008,5010,5013],{"class":100,"line":161},[98,5006,5007],{"class":3772},"            background-color",[98,5009,931],{"class":915},[98,5011,5012],{"class":911},"$color",[98,5014,1106],{"class":915},[98,5016,5017,5020,5022,5024,5026,5028,5030,5032],{"class":100,"line":166},[98,5018,5019],{"class":3772},"            border-color",[98,5021,931],{"class":915},[98,5023,4928],{"class":1120},[98,5025,1839],{"class":915},[98,5027,5012],{"class":911},[98,5029,938],{"class":915},[98,5031,4937],{"class":934},[98,5033,4853],{"class":915},[98,5035,5036],{"class":100,"line":172},[98,5037,3494],{"class":915},[98,5039,5040],{"class":100,"line":178},[98,5041,3656],{"class":915},[98,5043,5044],{"class":100,"line":513},[98,5045,181],{"class":915},[13,5047,5048],{},"こうすると",[71,5050,5054],{"className":5051,"code":5052,"language":5053,"meta":79,"style":79},"language-css shiki shiki-themes material-theme-ocean",".btn {\n  background-color: #E60012;\n  border: 1px solid;\n  border-color: #9a000c;\n  border-radius: 5px;\n  padding: 10px;\n  text-align: center; }\n  .btn-red {\n    background-color: #E60012;\n    border-color: #9a000c; }\n  .btn-orange {\n    background-color: #F39800;\n    border-color: #a76800; }\n  .btn-yellow {\n    background-color: #FFF100;\n    border-color: #b3a900; }\n  .btn-green {\n    background-color: #009944;\n    border-color: #004d22; }\n  .btn-blue {\n    background-color: #0068B7;\n    border-color: #003d6b; }\n  .btn-purple {\n    background-color: #920783;\n    border-color: #490442; }\n","css",[28,5055,5056,5064,5078,5092,5106,5118,5130,5146,5156,5168,5182,5191,5203,5218,5227,5239,5254,5263,5275,5290,5299,5311,5326,5335,5347],{"__ignoreMap":79},[98,5057,5058,5060,5062],{"class":100,"line":101},[98,5059,1100],{"class":915},[98,5061,4891],{"class":2942},[98,5063,2448],{"class":915},[98,5065,5066,5069,5071,5074,5076],{"class":100,"line":107},[98,5067,5068],{"class":3772},"  background-color",[98,5070,931],{"class":915},[98,5072,5073],{"class":915}," #",[98,5075,4756],{"class":911},[98,5077,1106],{"class":915},[98,5079,5080,5083,5085,5088,5090],{"class":100,"line":113},[98,5081,5082],{"class":3772},"  border",[98,5084,931],{"class":915},[98,5086,5087],{"class":934}," 1px",[98,5089,4916],{"class":911},[98,5091,1106],{"class":915},[98,5093,5094,5097,5099,5101,5104],{"class":100,"line":119},[98,5095,5096],{"class":3772},"  border-color",[98,5098,931],{"class":915},[98,5100,5073],{"class":915},[98,5102,5103],{"class":911},"9a000c",[98,5105,1106],{"class":915},[98,5107,5108,5111,5113,5116],{"class":100,"line":125},[98,5109,5110],{"class":3772},"  border-radius",[98,5112,931],{"class":915},[98,5114,5115],{"class":934}," 5px",[98,5117,1106],{"class":915},[98,5119,5120,5123,5125,5128],{"class":100,"line":131},[98,5121,5122],{"class":3772},"  padding",[98,5124,931],{"class":915},[98,5126,5127],{"class":934}," 10px",[98,5129,1106],{"class":915},[98,5131,5132,5135,5137,5140,5143],{"class":100,"line":137},[98,5133,5134],{"class":3772},"  text-align",[98,5136,931],{"class":915},[98,5138,5139],{"class":911}," center",[98,5141,5142],{"class":915},";",[98,5144,5145],{"class":915}," }\n",[98,5147,5148,5151,5154],{"class":100,"line":143},[98,5149,5150],{"class":915},"  .",[98,5152,5153],{"class":2942},"btn-red",[98,5155,2448],{"class":915},[98,5157,5158,5160,5162,5164,5166],{"class":100,"line":149},[98,5159,4681],{"class":3772},[98,5161,931],{"class":915},[98,5163,5073],{"class":915},[98,5165,4756],{"class":911},[98,5167,1106],{"class":915},[98,5169,5170,5172,5174,5176,5178,5180],{"class":100,"line":155},[98,5171,4923],{"class":3772},[98,5173,931],{"class":915},[98,5175,5073],{"class":915},[98,5177,5103],{"class":911},[98,5179,5142],{"class":915},[98,5181,5145],{"class":915},[98,5183,5184,5186,5189],{"class":100,"line":161},[98,5185,5150],{"class":915},[98,5187,5188],{"class":2942},"btn-orange",[98,5190,2448],{"class":915},[98,5192,5193,5195,5197,5199,5201],{"class":100,"line":166},[98,5194,4681],{"class":3772},[98,5196,931],{"class":915},[98,5198,5073],{"class":915},[98,5200,4774],{"class":911},[98,5202,1106],{"class":915},[98,5204,5205,5207,5209,5211,5214,5216],{"class":100,"line":172},[98,5206,4923],{"class":3772},[98,5208,931],{"class":915},[98,5210,5073],{"class":915},[98,5212,5213],{"class":911},"a76800",[98,5215,5142],{"class":915},[98,5217,5145],{"class":915},[98,5219,5220,5222,5225],{"class":100,"line":178},[98,5221,5150],{"class":915},[98,5223,5224],{"class":2942},"btn-yellow",[98,5226,2448],{"class":915},[98,5228,5229,5231,5233,5235,5237],{"class":100,"line":513},[98,5230,4681],{"class":3772},[98,5232,931],{"class":915},[98,5234,5073],{"class":915},[98,5236,4791],{"class":911},[98,5238,1106],{"class":915},[98,5240,5241,5243,5245,5247,5250,5252],{"class":100,"line":519},[98,5242,4923],{"class":3772},[98,5244,931],{"class":915},[98,5246,5073],{"class":915},[98,5248,5249],{"class":911},"b3a900",[98,5251,5142],{"class":915},[98,5253,5145],{"class":915},[98,5255,5256,5258,5261],{"class":100,"line":525},[98,5257,5150],{"class":915},[98,5259,5260],{"class":2942},"btn-green",[98,5262,2448],{"class":915},[98,5264,5265,5267,5269,5271,5273],{"class":100,"line":531},[98,5266,4681],{"class":3772},[98,5268,931],{"class":915},[98,5270,5073],{"class":915},[98,5272,4810],{"class":911},[98,5274,1106],{"class":915},[98,5276,5277,5279,5281,5283,5286,5288],{"class":100,"line":537},[98,5278,4923],{"class":3772},[98,5280,931],{"class":915},[98,5282,5073],{"class":915},[98,5284,5285],{"class":911},"004d22",[98,5287,5142],{"class":915},[98,5289,5145],{"class":915},[98,5291,5292,5294,5297],{"class":100,"line":543},[98,5293,5150],{"class":915},[98,5295,5296],{"class":2942},"btn-blue",[98,5298,2448],{"class":915},[98,5300,5301,5303,5305,5307,5309],{"class":100,"line":549},[98,5302,4681],{"class":3772},[98,5304,931],{"class":915},[98,5306,5073],{"class":915},[98,5308,4828],{"class":911},[98,5310,1106],{"class":915},[98,5312,5313,5315,5317,5319,5322,5324],{"class":100,"line":555},[98,5314,4923],{"class":3772},[98,5316,931],{"class":915},[98,5318,5073],{"class":915},[98,5320,5321],{"class":911},"003d6b",[98,5323,5142],{"class":915},[98,5325,5145],{"class":915},[98,5327,5328,5330,5333],{"class":100,"line":561},[98,5329,5150],{"class":915},[98,5331,5332],{"class":2942},"btn-purple",[98,5334,2448],{"class":915},[98,5336,5337,5339,5341,5343,5345],{"class":100,"line":567},[98,5338,4681],{"class":3772},[98,5340,931],{"class":915},[98,5342,5073],{"class":915},[98,5344,4846],{"class":911},[98,5346,1106],{"class":915},[98,5348,5349,5351,5353,5355,5358,5360],{"class":100,"line":573},[98,5350,4923],{"class":3772},[98,5352,931],{"class":915},[98,5354,5073],{"class":915},[98,5356,5357],{"class":911},"490442",[98,5359,5142],{"class":915},[98,5361,5145],{"class":915},[13,5363,5364],{},"それぞれの色パターンのボタンクラスができました。実際に適用してみると以下の通りです。",[5366,5367],"image-render",{":src":5368},"'useful-sass-mixins\u002Fsch2021-06-28 22.50.04.png'",[13,5370,5371],{},"mapとeachを使うとカラーパターンのクラスを簡単に実装できます。",[328,5373,5374],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .s6YsC, html code.shiki .s6YsC{--shiki-default:#B2CCD6}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}",{"title":79,"searchDepth":113,"depth":113,"links":5376},[5377,5378],{"id":3748,"depth":107,"text":3748},{"id":4710,"depth":107,"text":4710},[342],"2021-06-28","設定しておきたいmixinと記述週",{},"\u002Farticles\u002Fuseful-sass-mixins",{"title":3723,"description":5381},"articles\u002Fuseful-sass-mixins",[5053],"useful-sass-mixins\u002Fthumbnail.png","ZczNQ4FtkqMbeh7MFTHHTJ3BRi4RWjEA8rwabquN6pI",{"id":5390,"title":5391,"body":5392,"category":5733,"createdAt":5734,"description":5735,"extension":345,"index":346,"meta":5736,"navigation":348,"path":5737,"publish":348,"seo":5738,"series":346,"seriesTitle":346,"stem":5739,"tag":5740,"thumbnail":346,"updatedAt":346,"__hash__":5742},"articles\u002Farticles\u002Ffirebase-emulator-port-token.md","ポートが使用されていてFirebaseエミュレータが起動できない時の対処法",{"type":10,"value":5393,"toc":5731},[5394,5397,5403,5406,5412,5419,5425,5605,5608,5611,5624,5627,5700,5703,5716,5719,5725,5728],[13,5395,5396],{},"こんにちはjunです、最近Firebaseを使用したアプリケーション開発をしています。エミュレータがあるのでそこでFirestoreやAuthenticationのテストをしています。ある日、開発の続きをやろうとしてエミュレータを起動させました。",[71,5398,5401],{"className":5399,"code":5400,"language":76},[74],"firebase emulators:start\n",[28,5402,5400],{"__ignoreMap":79},[13,5404,5405],{},"しかし",[71,5407,5410],{"className":5408,"code":5409,"language":76},[74],"⚠  firestore: Port 8081 is not open on localhost, could not start Firestore Emulator.\n⚠  firestore: To select a different host\u002Fport, specify that host\u002Fport in a firebase.json config file:\n      {\n        \u002F\u002F ...\n        \"emulators\": {\n          \"firestore\": {\n            \"host\": \"HOST\",\n            \"port\": \"PORT\"\n          }\n        }\n      }\ni  emulators: Shutting down emulators.\n\nError: Could not start Firestore Emulator, port taken.\n",[28,5411,5409],{"__ignoreMap":79},[13,5413,5414,5415,5418],{},"あらら、、起動に失敗してしまいました。エミュレーター二回目の起動の時によく発生します。原因は",[28,5416,5417],{},"Could not start Firestore Emulator, port taken.","とある様にポートが使用中だからです。",[13,5420,5421,5424],{},[28,5422,5423],{},"firebase.json","にはエミュレーターのポートを定義できます。私の場合は以下の通りです。",[71,5426,5430],{"className":5427,"code":5428,"language":5429,"meta":79,"style":79},"language-json shiki shiki-themes material-theme-ocean","\"emulators\": {\n    \"auth\": {\n        \"port\": 9099\n    },\n    \"functions\": {\n        \"port\": 5001\n    },\n    \"firestore\": {\n        \"port\": 8081\n    },\n    \"database\": {\n        \"port\": 8082\n    },\n    \"ui\": {\n        \"enabled\": true\n    }\n},\n","json",[28,5431,5432,5445,5458,5473,5478,5491,5504,5508,5521,5534,5538,5551,5564,5568,5581,5595,5599],{"__ignoreMap":79},[98,5433,5434,5436,5439,5441,5443],{"class":100,"line":101},[98,5435,946],{"class":915},[98,5437,5438],{"class":949},"emulators",[98,5440,946],{"class":915},[98,5442,3915],{"class":911},[98,5444,140],{"class":915},[98,5446,5447,5449,5452,5454,5456],{"class":100,"line":107},[98,5448,4743],{"class":915},[98,5450,5451],{"class":907},"auth",[98,5453,946],{"class":915},[98,5455,931],{"class":915},[98,5457,2448],{"class":915},[98,5459,5460,5463,5466,5468,5470],{"class":100,"line":113},[98,5461,5462],{"class":915},"        \"",[98,5464,5465],{"class":2942},"port",[98,5467,946],{"class":915},[98,5469,931],{"class":915},[98,5471,5472],{"class":934}," 9099\n",[98,5474,5475],{"class":100,"line":119},[98,5476,5477],{"class":915},"    },\n",[98,5479,5480,5482,5485,5487,5489],{"class":100,"line":125},[98,5481,4743],{"class":915},[98,5483,5484],{"class":907},"functions",[98,5486,946],{"class":915},[98,5488,931],{"class":915},[98,5490,2448],{"class":915},[98,5492,5493,5495,5497,5499,5501],{"class":100,"line":131},[98,5494,5462],{"class":915},[98,5496,5465],{"class":2942},[98,5498,946],{"class":915},[98,5500,931],{"class":915},[98,5502,5503],{"class":934}," 5001\n",[98,5505,5506],{"class":100,"line":137},[98,5507,5477],{"class":915},[98,5509,5510,5512,5515,5517,5519],{"class":100,"line":143},[98,5511,4743],{"class":915},[98,5513,5514],{"class":907},"firestore",[98,5516,946],{"class":915},[98,5518,931],{"class":915},[98,5520,2448],{"class":915},[98,5522,5523,5525,5527,5529,5531],{"class":100,"line":149},[98,5524,5462],{"class":915},[98,5526,5465],{"class":2942},[98,5528,946],{"class":915},[98,5530,931],{"class":915},[98,5532,5533],{"class":934}," 8081\n",[98,5535,5536],{"class":100,"line":155},[98,5537,5477],{"class":915},[98,5539,5540,5542,5545,5547,5549],{"class":100,"line":161},[98,5541,4743],{"class":915},[98,5543,5544],{"class":907},"database",[98,5546,946],{"class":915},[98,5548,931],{"class":915},[98,5550,2448],{"class":915},[98,5552,5553,5555,5557,5559,5561],{"class":100,"line":166},[98,5554,5462],{"class":915},[98,5556,5465],{"class":2942},[98,5558,946],{"class":915},[98,5560,931],{"class":915},[98,5562,5563],{"class":934}," 8082\n",[98,5565,5566],{"class":100,"line":172},[98,5567,5477],{"class":915},[98,5569,5570,5572,5575,5577,5579],{"class":100,"line":178},[98,5571,4743],{"class":915},[98,5573,5574],{"class":907},"ui",[98,5576,946],{"class":915},[98,5578,931],{"class":915},[98,5580,2448],{"class":915},[98,5582,5583,5585,5588,5590,5592],{"class":100,"line":513},[98,5584,5462],{"class":915},[98,5586,5587],{"class":2942},"enabled",[98,5589,946],{"class":915},[98,5591,931],{"class":915},[98,5593,5594],{"class":915}," true\n",[98,5596,5597],{"class":100,"line":519},[98,5598,3656],{"class":915},[98,5600,5601,5603],{"class":100,"line":525},[98,5602,1316],{"class":915},[98,5604,2493],{"class":911},[13,5606,5607],{},"とりあえず8081と8082でどんなプロセスが動いているか確かめましょう。（この時はfirestoreだけでなくdatabaseも取られていました。）",[13,5609,5610],{},"Macで任意ポートで使用されているプロセスを調べる時は以下の様なコマンドを打ちます。",[71,5612,5614],{"className":2909,"code":5613,"language":2911,"meta":79,"style":79},"lsof -i:PORT\n",[28,5615,5616],{"__ignoreMap":79},[98,5617,5618,5621],{"class":100,"line":101},[98,5619,5620],{"class":2942},"lsof",[98,5622,5623],{"class":949}," -i:PORT\n",[13,5625,5626],{},"なので今回は",[71,5628,5630],{"className":2909,"code":5629,"language":2911,"meta":79,"style":79},"lsof -i:8081\nOMMAND  PID       USER   FD   TYPE            DEVICE SIZE\u002FOFF NODE NAME\njava    2322       jun   93u  IPv6 0x3f5922436f29fd5      0t0  TCP localhost:sunproxyadmin (LISTEN)\n",[28,5631,5632,5639,5668],{"__ignoreMap":79},[98,5633,5634,5636],{"class":100,"line":101},[98,5635,5620],{"class":2942},[98,5637,5638],{"class":949}," -i:8081\n",[98,5640,5641,5644,5647,5650,5653,5656,5659,5662,5665],{"class":100,"line":107},[98,5642,5643],{"class":2942},"OMMAND",[98,5645,5646],{"class":949},"  PID",[98,5648,5649],{"class":949},"       USER",[98,5651,5652],{"class":949},"   FD",[98,5654,5655],{"class":949},"   TYPE",[98,5657,5658],{"class":949},"            DEVICE",[98,5660,5661],{"class":949}," SIZE\u002FOFF",[98,5663,5664],{"class":949}," NODE",[98,5666,5667],{"class":949}," NAME\n",[98,5669,5670,5673,5676,5679,5682,5685,5688,5691,5694,5697],{"class":100,"line":113},[98,5671,5672],{"class":2942},"java",[98,5674,5675],{"class":934},"    2322",[98,5677,5678],{"class":949},"       jun",[98,5680,5681],{"class":949},"   93u",[98,5683,5684],{"class":949},"  IPv6",[98,5686,5687],{"class":934}," 0x3f5922436f29fd5",[98,5689,5690],{"class":949},"      0t0",[98,5692,5693],{"class":949},"  TCP",[98,5695,5696],{"class":949}," localhost:sunproxyadmin",[98,5698,5699],{"class":911}," (LISTEN)\n",[13,5701,5702],{},"なんだろう？とりえずエミュレーター系だと思う。なのでこのプロセスをkillする",[71,5704,5706],{"className":2909,"code":5705,"language":2911,"meta":79,"style":79},"kill 2322\n",[28,5707,5708],{"__ignoreMap":79},[98,5709,5710,5713],{"class":100,"line":101},[98,5711,5712],{"class":1120},"kill",[98,5714,5715],{"class":934}," 2322\n",[13,5717,5718],{},"そしてもう一度起動",[71,5720,5723],{"className":5721,"code":5722,"language":76},[74],"firebase emulators:start\n┌─────────────────────────────────────────────────────────────┐\n│ ✔  All emulators ready! It is now safe to connect your app. │\n│ i  View Emulator UI at http:\u002F\u002Flocalhost:4002                │\n└─────────────────────────────────────────────────────────────┘\n",[28,5724,5722],{"__ignoreMap":79},[13,5726,5727],{},"OK!これで起動完了。以上がFirestore、Databaseでポートが取られて起動できない時の対処法です。Authとかは起きないのに、なぜかfirestoreとDatabaseだけ発生します。。",[328,5729,5730],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}",{"title":79,"searchDepth":113,"depth":113,"links":5732},[],[342],"2021-05-31","ポートが使用されていてFirebaseエミュレータが起動的無い時の対処法",{},"\u002Farticles\u002Ffirebase-emulator-port-token",{"title":5391,"description":5735},"articles\u002Ffirebase-emulator-port-token",[2856,5741],"firebase","WZCWojY2PQc1aA0-QDiGPzMKO6InsuB6Hbr1wZtO8aI",{"id":5744,"title":5745,"body":5746,"category":6295,"createdAt":6296,"description":6297,"extension":345,"index":346,"meta":6298,"navigation":348,"path":6299,"publish":348,"seo":6300,"series":346,"seriesTitle":346,"stem":6301,"tag":6302,"thumbnail":6304,"updatedAt":346,"__hash__":6305},"articles\u002Farticles\u002Fbag-html-break-tag.md","white-space： pre;で要素内で生じる文章の隙間、インテンドの原因。",{"type":10,"value":5747,"toc":6293},[5748,5755,5759,5762,5952,5966,5978,5985,6110,6116,6119,6122,6284,6290],[13,5749,5750,5751,5754],{},"こんにちはjunです。ある日、vue.jsを使用して",[28,5752,5753],{},"textarea","の中の文章をリアルタイムにレンダーするような機能を実装しました。その時、改行文章に謎のインテンドが入り、困りました。こんな感じです。",[5366,5756],{":src":5757,":width":5758,":center":1466},"'_mix\u002Fsch-2021-05-04 21.53.14.png'","'300px'",[13,5760,5761],{},"ソースは以下の感じ（かなり簡略化してます。）",[71,5763,5766],{"className":5764,"code":5765,"language":2637,"meta":79,"style":79},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">\n        {{test}}\n        \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n    \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    data(){\n        return{\n            test:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[28,5767,5768,5779,5787,5808,5813,5862,5871,5880,5888,5897,5907,5915,5922,5932,5936,5940,5944],{"__ignoreMap":79},[98,5769,5770,5773,5776],{"class":100,"line":101},[98,5771,5772],{"class":915},"\u003C",[98,5774,5775],{"class":927},"template",[98,5777,5778],{"class":915},">\n",[98,5780,5781,5783,5785],{"class":100,"line":107},[98,5782,5772],{"class":915},[98,5784,1224],{"class":927},[98,5786,5778],{"class":915},[98,5788,5789,5792,5794,5797,5799,5801,5804,5806],{"class":100,"line":113},[98,5790,5791],{"class":915},"    \u003C",[98,5793,1224],{"class":927},[98,5795,5796],{"class":907}," style",[98,5798,916],{"class":915},[98,5800,946],{"class":915},[98,5802,5803],{"class":949},"white-space:pre;",[98,5805,946],{"class":915},[98,5807,5778],{"class":915},[98,5809,5810],{"class":100,"line":119},[98,5811,5812],{"class":911},"        {{test}}\n",[98,5814,5815,5818,5820,5823,5825,5827,5829,5831,5834,5836,5838,5841,5843,5846,5848,5850,5853,5855,5858,5860],{"class":100,"line":125},[98,5816,5817],{"class":915},"        \u003C",[98,5819,5753],{"class":927},[98,5821,5822],{"class":907}," v-model",[98,5824,916],{"class":915},[98,5826,946],{"class":915},[98,5828,2715],{"class":949},[98,5830,946],{"class":915},[98,5832,5833],{"class":907},"cols",[98,5835,916],{"class":915},[98,5837,946],{"class":915},[98,5839,5840],{"class":949},"30",[98,5842,946],{"class":915},[98,5844,5845],{"class":907}," rows",[98,5847,916],{"class":915},[98,5849,946],{"class":915},[98,5851,5852],{"class":949},"10",[98,5854,946],{"class":915},[98,5856,5857],{"class":915},">\u003C\u002F",[98,5859,5753],{"class":927},[98,5861,5778],{"class":915},[98,5863,5864,5867,5869],{"class":100,"line":131},[98,5865,5866],{"class":915},"    \u003C\u002F",[98,5868,1224],{"class":927},[98,5870,5778],{"class":915},[98,5872,5873,5876,5878],{"class":100,"line":137},[98,5874,5875],{"class":915},"\u003C\u002F",[98,5877,1224],{"class":927},[98,5879,5778],{"class":915},[98,5881,5882,5884,5886],{"class":100,"line":143},[98,5883,5875],{"class":915},[98,5885,5775],{"class":927},[98,5887,5778],{"class":915},[98,5889,5890,5892,5895],{"class":100,"line":149},[98,5891,5772],{"class":915},[98,5893,5894],{"class":927},"script",[98,5896,5778],{"class":915},[98,5898,5899,5902,5905],{"class":100,"line":155},[98,5900,5901],{"class":1852},"export",[98,5903,5904],{"class":1852}," default",[98,5906,2448],{"class":915},[98,5908,5909,5912],{"class":100,"line":161},[98,5910,5911],{"class":927},"    data",[98,5913,5914],{"class":915},"(){\n",[98,5916,5917,5920],{"class":100,"line":166},[98,5918,5919],{"class":1852},"        return",[98,5921,140],{"class":915},[98,5923,5924,5927,5929],{"class":100,"line":172},[98,5925,5926],{"class":927},"            test",[98,5928,931],{"class":915},[98,5930,5931],{"class":915},"''\n",[98,5933,5934],{"class":100,"line":178},[98,5935,3494],{"class":915},[98,5937,5938],{"class":100,"line":513},[98,5939,3656],{"class":915},[98,5941,5942],{"class":100,"line":519},[98,5943,181],{"class":915},[98,5945,5946,5948,5950],{"class":100,"line":525},[98,5947,5875],{"class":915},[98,5949,5894],{"class":927},[98,5951,5778],{"class":915},[13,5953,5954,5955,5958,5959,5962,5963,5965],{},"とても簡単で",[28,5956,5957],{},"v-model","を使用してその",[28,5960,5961],{},"data()","を表示してあるだけです。そしてCSSでは",[28,5964,5803],{},"を指定して、改行コードが存在したらそこで改行するようにします。",[1224,5967,5970,5971],{"className":5968},[1227,5969],"alert-success","\nCSS の white-space プロパティは、要素内のホワイトスペースをどのように扱うかを設定します。\n",[5972,5973,5974],"small",{},[196,5975,5977],{"href":5976,"target":1232},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FCSS\u002Fwhite-space","mozilla.org",[13,5979,5980,5981,5984],{},"ただし上図のように謎のインテンドが最初の改行にあります。なぜ生じしてしまうのかを調べたところ、 ",[1242,5982,5983],{},"エディター上でのインテンド"," が原因でした。以下のようにファイルを直してみます。",[71,5986,5988],{"className":5764,"code":5987,"language":2637,"meta":79,"style":79},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">\n{{test}}\n        \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n    \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003C\u002Fscript>\n",[28,5989,5990,5998,6006,6024,6029,6071,6079,6087,6095,6099],{"__ignoreMap":79},[98,5991,5992,5994,5996],{"class":100,"line":101},[98,5993,5772],{"class":915},[98,5995,5775],{"class":927},[98,5997,5778],{"class":915},[98,5999,6000,6002,6004],{"class":100,"line":107},[98,6001,5772],{"class":915},[98,6003,1224],{"class":927},[98,6005,5778],{"class":915},[98,6007,6008,6010,6012,6014,6016,6018,6020,6022],{"class":100,"line":113},[98,6009,5791],{"class":915},[98,6011,1224],{"class":927},[98,6013,5796],{"class":907},[98,6015,916],{"class":915},[98,6017,946],{"class":915},[98,6019,5803],{"class":949},[98,6021,946],{"class":915},[98,6023,5778],{"class":915},[98,6025,6026],{"class":100,"line":119},[98,6027,6028],{"class":911},"{{test}}\n",[98,6030,6031,6033,6035,6037,6039,6041,6043,6045,6047,6049,6051,6053,6055,6057,6059,6061,6063,6065,6067,6069],{"class":100,"line":125},[98,6032,5817],{"class":915},[98,6034,5753],{"class":927},[98,6036,5822],{"class":907},[98,6038,916],{"class":915},[98,6040,946],{"class":915},[98,6042,2715],{"class":949},[98,6044,946],{"class":915},[98,6046,5833],{"class":907},[98,6048,916],{"class":915},[98,6050,946],{"class":915},[98,6052,5840],{"class":949},[98,6054,946],{"class":915},[98,6056,5845],{"class":907},[98,6058,916],{"class":915},[98,6060,946],{"class":915},[98,6062,5852],{"class":949},[98,6064,946],{"class":915},[98,6066,5857],{"class":915},[98,6068,5753],{"class":927},[98,6070,5778],{"class":915},[98,6072,6073,6075,6077],{"class":100,"line":131},[98,6074,5866],{"class":915},[98,6076,1224],{"class":927},[98,6078,5778],{"class":915},[98,6080,6081,6083,6085],{"class":100,"line":137},[98,6082,5875],{"class":915},[98,6084,1224],{"class":927},[98,6086,5778],{"class":915},[98,6088,6089,6091,6093],{"class":100,"line":143},[98,6090,5875],{"class":915},[98,6092,5775],{"class":927},[98,6094,5778],{"class":915},[98,6096,6097],{"class":100,"line":149},[98,6098,389],{"emptyLinePlaceholder":348},[98,6100,6101,6103,6106,6108],{"class":100,"line":155},[98,6102,5772],{"class":915},[98,6104,6105],{"class":911},"\u002F",[98,6107,5894],{"class":927},[98,6109,5778],{"class":915},[13,6111,6112,6115],{},[28,6113,6114],{},"{{text}}","の箇所を一番左につけることでなぜか、改行の際のインテンドがなくなりました。",[5366,6117],{":src":6118,":width":5758,":center":1466},"'_mix\u002Fsch-2021-05-04 22.01.03.png'",[13,6120,6121],{},"またはこのようにタグを改行させず、一行内に書くことでも解決できます。",[71,6123,6125],{"className":5764,"code":6124,"language":2637,"meta":79,"style":79},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">{{test}}\u003C\u002Fdiv>\n    \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    data(){\n        return{\n            test:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[28,6126,6127,6135,6143,6170,6212,6220,6228,6236,6244,6250,6256,6264,6268,6272,6276],{"__ignoreMap":79},[98,6128,6129,6131,6133],{"class":100,"line":101},[98,6130,5772],{"class":915},[98,6132,5775],{"class":927},[98,6134,5778],{"class":915},[98,6136,6137,6139,6141],{"class":100,"line":107},[98,6138,5772],{"class":915},[98,6140,1224],{"class":927},[98,6142,5778],{"class":915},[98,6144,6145,6147,6149,6151,6153,6155,6157,6159,6161,6164,6166,6168],{"class":100,"line":113},[98,6146,5791],{"class":915},[98,6148,1224],{"class":927},[98,6150,5796],{"class":907},[98,6152,916],{"class":915},[98,6154,946],{"class":915},[98,6156,5803],{"class":949},[98,6158,946],{"class":915},[98,6160,1258],{"class":915},[98,6162,6163],{"class":911},"{{test}}",[98,6165,5875],{"class":915},[98,6167,1224],{"class":927},[98,6169,5778],{"class":915},[98,6171,6172,6174,6176,6178,6180,6182,6184,6186,6188,6190,6192,6194,6196,6198,6200,6202,6204,6206,6208,6210],{"class":100,"line":119},[98,6173,5791],{"class":915},[98,6175,5753],{"class":927},[98,6177,5822],{"class":907},[98,6179,916],{"class":915},[98,6181,946],{"class":915},[98,6183,2715],{"class":949},[98,6185,946],{"class":915},[98,6187,5833],{"class":907},[98,6189,916],{"class":915},[98,6191,946],{"class":915},[98,6193,5840],{"class":949},[98,6195,946],{"class":915},[98,6197,5845],{"class":907},[98,6199,916],{"class":915},[98,6201,946],{"class":915},[98,6203,5852],{"class":949},[98,6205,946],{"class":915},[98,6207,5857],{"class":915},[98,6209,5753],{"class":927},[98,6211,5778],{"class":915},[98,6213,6214,6216,6218],{"class":100,"line":125},[98,6215,5875],{"class":915},[98,6217,1224],{"class":927},[98,6219,5778],{"class":915},[98,6221,6222,6224,6226],{"class":100,"line":131},[98,6223,5875],{"class":915},[98,6225,5775],{"class":927},[98,6227,5778],{"class":915},[98,6229,6230,6232,6234],{"class":100,"line":137},[98,6231,5772],{"class":915},[98,6233,5894],{"class":927},[98,6235,5778],{"class":915},[98,6237,6238,6240,6242],{"class":100,"line":143},[98,6239,5901],{"class":1852},[98,6241,5904],{"class":1852},[98,6243,2448],{"class":915},[98,6245,6246,6248],{"class":100,"line":149},[98,6247,5911],{"class":927},[98,6249,5914],{"class":915},[98,6251,6252,6254],{"class":100,"line":155},[98,6253,5919],{"class":1852},[98,6255,140],{"class":915},[98,6257,6258,6260,6262],{"class":100,"line":161},[98,6259,5926],{"class":927},[98,6261,931],{"class":915},[98,6263,5931],{"class":915},[98,6265,6266],{"class":100,"line":166},[98,6267,3494],{"class":915},[98,6269,6270],{"class":100,"line":172},[98,6271,3656],{"class":915},[98,6273,6274],{"class":100,"line":178},[98,6275,181],{"class":915},[98,6277,6278,6280,6282],{"class":100,"line":513},[98,6279,5875],{"class":915},[98,6281,5894],{"class":927},[98,6283,5778],{"class":915},[13,6285,6286,6287,6289],{},"なぜ",[28,6288,5803],{},"で謎インテンドが生じてしまうのかわかりませんが、改行コードが入る箇所をエディターで整形する際は気をつけたほうがいいかもしれません。",[328,6291,6292],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":79,"searchDepth":113,"depth":113,"links":6294},[],[342],"2021-05-24","white-space： pre;で要素内で生じる、文章の隙間、インテンドの原因。",{},"\u002Farticles\u002Fbag-html-break-tag",{"title":5745,"description":6297},"articles\u002Fbag-html-break-tag",[6303,5053,2637],"html","_mix\u002Fsch-2021-05-04 21.53.14.png","Uglb2nJDSJTaiJVJS_4tGrhobJMBKtzio_BSkBLsen0",{"id":6307,"title":6308,"body":6309,"category":6585,"createdAt":6586,"description":6587,"extension":345,"index":346,"meta":6588,"navigation":348,"path":6589,"publish":348,"seo":6590,"series":346,"seriesTitle":346,"stem":6591,"tag":6592,"thumbnail":346,"updatedAt":346,"__hash__":6594},"articles\u002Farticles\u002Fclick-event-on-lable.md","label要素と関連付けされたinput要素にクリックイベントを付与すると2回実行される。",{"type":10,"value":6310,"toc":6579},[6311,6314,6518,6526,6533,6537,6540,6547,6551,6560,6564,6570,6573,6576],[13,6312,6313],{},"こんにちはjunです。フォームとしての要素、ボタンとしての要素を掛け合わせて以下のようなものを作成していました。",[71,6315,6318],{"className":6316,"code":6317,"language":6303,"meta":79,"style":79},"language-html shiki shiki-themes material-theme-ocean","\u003Clabel class=\"c-button\" for=\"form-input\">\n    \u003Cinput data-product_id=\"1\" id=\"form-input\" type=\"checkbox\" name=\"form-input\" value=\"\">\n    \u003Cspan class=\"text\">まとめて購入\u003C\u002Fspan>\n\u003C\u002Flabel>\n\n\u003Cscript>\n    $('.c-button').on('click',function(){\n        \u002F\u002F ...\n    })\n\u003C\u002Fscript>\n",[28,6319,6320,6353,6415,6442,6450,6454,6462,6499,6504,6510],{"__ignoreMap":79},[98,6321,6322,6324,6327,6330,6332,6334,6337,6339,6342,6344,6346,6349,6351],{"class":100,"line":101},[98,6323,5772],{"class":915},[98,6325,6326],{"class":927},"label",[98,6328,6329],{"class":907}," class",[98,6331,916],{"class":915},[98,6333,946],{"class":915},[98,6335,6336],{"class":949},"c-button",[98,6338,946],{"class":915},[98,6340,6341],{"class":907}," for",[98,6343,916],{"class":915},[98,6345,946],{"class":915},[98,6347,6348],{"class":949},"form-input",[98,6350,946],{"class":915},[98,6352,5778],{"class":915},[98,6354,6355,6357,6360,6363,6365,6367,6369,6371,6374,6376,6378,6380,6382,6385,6387,6389,6392,6394,6397,6399,6401,6403,6405,6408,6410,6413],{"class":100,"line":107},[98,6356,5791],{"class":915},[98,6358,6359],{"class":927},"input",[98,6361,6362],{"class":907}," data-product_id",[98,6364,916],{"class":915},[98,6366,946],{"class":915},[98,6368,935],{"class":949},[98,6370,946],{"class":915},[98,6372,6373],{"class":907}," id",[98,6375,916],{"class":915},[98,6377,946],{"class":915},[98,6379,6348],{"class":949},[98,6381,946],{"class":915},[98,6383,6384],{"class":907}," type",[98,6386,916],{"class":915},[98,6388,946],{"class":915},[98,6390,6391],{"class":949},"checkbox",[98,6393,946],{"class":915},[98,6395,6396],{"class":907}," name",[98,6398,916],{"class":915},[98,6400,946],{"class":915},[98,6402,6348],{"class":949},[98,6404,946],{"class":915},[98,6406,6407],{"class":907}," value",[98,6409,916],{"class":915},[98,6411,6412],{"class":915},"\"\"",[98,6414,5778],{"class":915},[98,6416,6417,6419,6421,6423,6425,6427,6429,6431,6433,6436,6438,6440],{"class":100,"line":113},[98,6418,5791],{"class":915},[98,6420,98],{"class":927},[98,6422,6329],{"class":907},[98,6424,916],{"class":915},[98,6426,946],{"class":915},[98,6428,76],{"class":949},[98,6430,946],{"class":915},[98,6432,1258],{"class":915},[98,6434,6435],{"class":911},"まとめて購入",[98,6437,5875],{"class":915},[98,6439,98],{"class":927},[98,6441,5778],{"class":915},[98,6443,6444,6446,6448],{"class":100,"line":119},[98,6445,5875],{"class":915},[98,6447,6326],{"class":927},[98,6449,5778],{"class":915},[98,6451,6452],{"class":100,"line":125},[98,6453,389],{"emptyLinePlaceholder":348},[98,6455,6456,6458,6460],{"class":100,"line":131},[98,6457,5772],{"class":915},[98,6459,5894],{"class":927},[98,6461,5778],{"class":915},[98,6463,6464,6467,6469,6471,6474,6476,6478,6480,6483,6485,6487,6490,6492,6494,6497],{"class":100,"line":137},[98,6465,6466],{"class":1120},"    $",[98,6468,1839],{"class":911},[98,6470,2738],{"class":915},[98,6472,6473],{"class":949},".c-button",[98,6475,2738],{"class":915},[98,6477,1864],{"class":911},[98,6479,1100],{"class":915},[98,6481,6482],{"class":1120},"on",[98,6484,1839],{"class":911},[98,6486,2738],{"class":915},[98,6488,6489],{"class":949},"click",[98,6491,2738],{"class":915},[98,6493,938],{"class":915},[98,6495,6496],{"class":907},"function",[98,6498,5914],{"class":915},[98,6500,6501],{"class":100,"line":143},[98,6502,6503],{"class":1050},"        \u002F\u002F ...\n",[98,6505,6506,6508],{"class":100,"line":149},[98,6507,2817],{"class":915},[98,6509,794],{"class":911},[98,6511,6512,6514,6516],{"class":100,"line":155},[98,6513,5875],{"class":915},[98,6515,5894],{"class":927},[98,6517,5778],{"class":915},[13,6519,6520,6522,6523,6525],{},[28,6521,6326],{},"をクリックするとチェックボックスにチェックが入り、さらにクリックイベントも走るという仕組みです。",[28,6524,6359],{},"だけをクリックしても同じ動作になります。",[13,6527,6528,6529,6532],{},"しかしチェックをしてみると挙動が何故か変。私の場合はON・OFF的な処理をしていたので、inputをクリックすると正常に動き、labelだと処理が行われていないという現象に見舞われました。原因はタイトル通り、上記のような構成をjqueryで実装すると、labelをクリックすると",[28,6530,6531],{},"$('.c-button')","へのクリックイベントが2回走ることが原因です。対処としては3つほどあります。",[17,6534,6536],{"id":6535},"_1changeイベントに変更する","1：changeイベントに変更する",[13,6538,6539],{},"input要素を活かしたい場合はこれがベストだと思います。changeイベントはinputなどの入力値が変更された時に発火するイベントです。for属性を用いてinputと関連付けされいるので、labelをクリックすることでinputの値（チェックされたか）を変更させることができます。一方でinputだけをクリックしても発火します。",[13,6541,6542,6543,6546],{},"なぜクリックイベントが2回起きるのかがわかりませんが、for属性あたりとかがなんか関係しているのかもしれません。 ",[1242,6544,6545],{},"change属性であれば値が変更されたか否かでの発火条件となる","ので問題なくなります。",[17,6548,6550],{"id":6549},"_2inputだけにする","2:inputだけにする",[13,6552,6553,6555,6556,6559],{},[28,6554,6531],{},"を",[28,6557,6558],{},"$('.c-button input')","にします。そうすれば一応inputだけクリックした時に発火します。ただし、labelでボタンのスタイルを表現していたりする場合はこの手は微妙です。",[17,6561,6563],{"id":6562},"_3inputでなくアイコン画像にする","3:inputでなくアイコン・画像にする",[13,6565,6566,6567,6569],{},"もし",[28,6568,6359],{},"がフォーム送信的な意味をもたず実装しているならば（見た目だけ）、画像・アイコンで実装するというてもあります。その時はクラスを付与してアイコンを変えると言ったことが必要です。",[17,6571,6572],{"id":6572},"まとめ",[13,6574,6575],{},"上記の解決法では１が一番ベストです。vanillajsで上記のような構成を作るとなぜか発生しないので、jqueryの仕様なのかもしれません。",[328,6577,6578],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":79,"searchDepth":113,"depth":113,"links":6580},[6581,6582,6583,6584],{"id":6535,"depth":107,"text":6536},{"id":6549,"depth":107,"text":6550},{"id":6562,"depth":107,"text":6563},{"id":6572,"depth":107,"text":6572},[342],"2021-04-30","要注意なクリックイベント。input要素にクリックイベントをつけている場合は注意。",{},"\u002Farticles\u002Fclick-event-on-lable",{"title":6308,"description":6587},"articles\u002Fclick-event-on-lable",[2636,6303,6593],"jquery","EaIYy3tweEkOCbIAFQ9TqAjE0pXI6pYISdYQKN-YfEw",{"id":6596,"title":6597,"body":6598,"category":7007,"createdAt":7008,"description":6597,"extension":345,"index":346,"meta":7009,"navigation":348,"path":7010,"publish":348,"seo":7011,"series":346,"seriesTitle":346,"stem":7012,"tag":7013,"thumbnail":7015,"updatedAt":346,"__hash__":7016},"articles\u002Farticles\u002Fvps-ssh-first.md","VPSでやっておきたいSSHの最低限のセキュティ設定。",{"type":10,"value":6599,"toc":6995},[6600,6603,6606,6609,6624,6636,6639,6643,6646,6652,6655,6658,6666,6669,6672,6683,6686,6689,6692,6698,6701,6707,6714,6720,6750,6753,6765,6772,6778,6781,6784,6787,6790,6796,6799,6805,6812,6818,6827,6833,6841,6847,6854,6870,6873,6876,6883,6889,6907,6910,6916,6919,6925,6928,6933,6936,6939,6942,6948,6951,6954,6960,6970,6976,6979,6985,6988,6992],[13,6601,6602],{},"こんにちはjunです。webエンジニアとして働いていますが会社の人数が少なく、インフラの構築をすることがあります。と言ってもLAMP環境を作成するぐらいですけど。",[13,6604,6605],{},"構築は慣れてきましたがその中で、私が一番考えるのはセキュリティーです。構築するアプリケーションによってはセキュリティー設定はことなりますが、今回は自分でサーバを構築する時に最低限やった方がいいSSHの設定をメモがてら記事にしようと思います。",[13,6607,6608],{},"今回行う設定は以下の通りです。",[6610,6611,6612,6615,6618,6621],"ul",{},[2882,6613,6614],{},"rootユーザーのリモートログイン禁止化",[2882,6616,6617],{},"パスワード認証禁止と鍵認証化",[2882,6619,6620],{},"鍵認証の実装方法",[2882,6622,6623],{},"ポート変更とfirewallの設定",[1224,6625,6627,6628],{"className":6626},[1227,5969],"\nなお今回説明する環境\n",[6610,6629,6630,6633],{},[2882,6631,6632],{},"サービス：GMO conoha VPS",[2882,6634,6635],{},"OS：centos8",[13,6637,6638],{},"この設定をすべき理由や背景などから話すため、さっさと方法を知りたい場合は「root以外のユーザーを作成していく」から見てください。",[17,6640,6642],{"id":6641},"sshはめちゃくちゃ狙われている","SSHはめちゃくちゃ狙われている",[13,6644,6645],{},"SSHはリモートでサーバーを操作できる口のため、一番厳重にしなければなりません。あまり運用していないサーバー、購入したばかりでドメインと紐づけられていなくても世界中からBOTによる不正アクセス試行が発生します。私がVPSで購入してイメージが立った時も早速ログを見たところ以下の様になっていました。",[71,6647,6650],{"className":6648,"code":6649,"language":76},[74],"April  8 12:10:04 xxx-xxx-xx-xxx sshd[6887]: Failed password for root from 209.141.36.197 port 54506 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6891]: Failed password for invalid user oracle from 209.141.36.197 port 54518 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6892]: Failed password for invalid user test from 209.141.36.197 port 54512 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6889]: Failed password for root from 209.141.36.197 port 54520 ssh2\nApril  8 12:10:06 xxx-xxx-xx-xxx sshd[6904]: Failed password for root from 222.187.238.136 port 58496 ssh2\nApril  8 12:10:10 xxx-xxx-xx-xxx sshd[6904]: Failed password for root from 222.187.238.136 port 58496 ssh2\nApril  8 12:16:26 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:30 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:33 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:37 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:41 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:45 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:49 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:16:53 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:16:56 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:27:50 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\nApril  8 12:27:54 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\nApril  8 12:27:57 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\n",[28,6651,6649],{"__ignoreMap":79},[13,6653,6654],{},"これはSSHの接続失敗の履歴です、同じIPで定間隔でrootユーザーによるパスワード接続を試みています。これはパスワードリスト攻撃・総当たり攻撃というものです。確率は低いですがrootのパスワードが万が一にあった場合、サーバの最上権限であるrootが第三者に掌握されます。",[13,6656,6657],{},"ドメインに紐づけられておらずIPだけでもこの様にBOTがインターネットを徘徊して、脆弱なサーバを狙っています。VPSを購入したらすぐにデフォルトの設定を変えて、比較的安全なものに変更しましょう。",[1224,6659,6661,6662,6665],{"className":6660},[1227,1228],"\nターミナルで",[28,6663,6664],{},"whois","コマンドを使用してIPのwois情報を調べられます。登録された国などもわかります。ちなみに上記のIPのほとんどが中国でした。\n",[17,6667,6668],{"id":6668},"安全にするために変更する設定",[13,6670,6671],{},"デフォルトの設定から以下の変更を行います。",[6610,6673,6674,6677,6680],{},[2882,6675,6676],{},"rootによるリモートログインを禁止にする。",[2882,6678,6679],{},"SSHをパスワード認証でなく、鍵認証にする",[2882,6681,6682],{},"ポートを変更する",[13,6684,6685],{},"これらの設定は最低限行うべきものです。より強固にする場合は、色々と他に設定しますがまずはこれでいきましょう。",[33,6687,6688],{"id":6688},"root以外のユーザーを作成していく",[13,6690,6691],{},"最終的にはrootのリモートログインを禁止するため別の操作ユーザーを作成していきます。まずはrootでログインしましましょう。",[71,6693,6696],{"className":6694,"code":6695,"language":76},[74],"ssh root@123.456.78.901\n（IPなどは自分のものに置き換えてください）\n",[28,6697,6695],{"__ignoreMap":79},[13,6699,6700],{},"開発用・SSH接続用ユーザーを作成します。",[71,6702,6705],{"className":6703,"code":6704,"language":76},[74],"# useradd develop\n# passwd develop\n",[28,6706,6704],{"__ignoreMap":79},[13,6708,6709,6710,6713],{},"これでユーザーとそのパスワードが設定されました。次にそのユーザーを",[28,6711,6712],{},"wheel","グループに所属させます。",[71,6715,6718],{"className":6716,"code":6717,"language":76},[74],"# usermod -G wheel develop\n",[28,6719,6717],{"__ignoreMap":79},[13,6721,6722,6724,6725,6728,6729,6732,6733,6736,6737,6740,6741,6743,6744,6746,6747,6749],{},[28,6723,6712],{},"グループに所属することで",[28,6726,6727],{},"develop","が",[28,6730,6731],{},"sudo","を使用できる様になり、また",[28,6734,6735],{},"su","にてrootになることができます。",[28,6738,6739],{},"\u002Fetc\u002Fsudoers","では",[28,6742,6712],{},"グループで行える操作などを定義してあり、基本的にはrootを使用せずdevelopでsshログインをして操作します。yumで何かインストールしたい時とかは",[28,6745,6731],{},"したり",[28,6748,6735],{},"でrootになります。",[3221,6751,6752],{"id":6752},"wheelのみがsuできる様にする",[13,6754,6755,6756,6758,6759,6761,6762,6764],{},"デフォルトではsuでどのユーザーもrootになれます。",[28,6757,6727],{},"意外にもユーザは存在し、そのユーザーが狙われることもあります。そのため",[28,6760,6712],{},"グループに属しているユーザーだけが",[28,6763,6735],{},"を用いてrootになれる様にしましょう。",[13,6766,6767,6768,6771],{},"suの設定は",[28,6769,6770],{},"\u002Fetc\u002Fpam.d\u002Fsu","に記述されています。",[71,6773,6776],{"className":6774,"code":6775,"language":76},[74],"# vi \u002Fetc\u002Fpam.d\u002Fsu\n\n--------\n# コメントアウトしているこの箇所を外す\n# auth            required        pam_wheel.so use_uid\n↓\nauth            required        pam_wheel.so use_uid\n--------\n",[28,6777,6775],{"__ignoreMap":79},[13,6779,6780],{},"コメントアウトされている箇所を外します。これでsuでrootになるためにwheelグループに属したユーザーから行うという制限ができました。",[33,6782,6783],{"id":6783},"develop用のssh鍵を作成",[13,6785,6786],{},"現在sshはパスワードでログインできますが、最終的にはパスワード認証を禁止にします。そしてよりセキュアな鍵認証式に変更します。基本的にログインの手間やセキュリティ的に鍵認証にした方がいいです。鍵認証の原理は今回は省きます。それではdevelop用の鍵を作成します。",[13,6788,6789],{},"クライアント側で秘密鍵と公開書きを作成します。",[71,6791,6794],{"className":6792,"code":6793,"language":76},[74],"% ssh-keygen\nGenerating public\u002Fprivate rsa key pair.\nEnter file in which to save the key (\u002FUsers\u002Fyou\u002F.ssh\u002Fid_rsa): #id_rsaというファイル名でよければそのままEnter\nEnter passphrase (empty for no passphrase): 　#パースフレーズを設定する場合は入力。なければEnter\nEnter same passphrase again:\n",[28,6795,6793],{"__ignoreMap":79},[13,6797,6798],{},"これで秘密鍵と公開鍵が生成されます。秘密鍵をクライアントに置いておき、公開鍵をサーバに転送します。",[71,6800,6803],{"className":6801,"code":6802,"language":76},[74],"scp .\u002Fid_rsa.pub develop@123.456.78.902:~\u002F\n",[28,6804,6802],{"__ignoreMap":79},[13,6806,6807,6808,6811],{},"サーバー側に戻ります。developのホームディレクトリに",[28,6809,6810],{},".ssh","というディレクトリがあるかを確認します。",[71,6813,6816],{"className":6814,"code":6815,"language":76},[74],"$ ls -a ~\u002F\n",[28,6817,6815],{"__ignoreMap":79},[13,6819,6820,6822,6823,6826],{},[28,6821,6810],{},"は隠しフォルダなので",[28,6824,6825],{},"ls -a","を使用します。無い場合はディレクトリを作成します。今回は無かったとしましょう。",[71,6828,6831],{"className":6829,"code":6830,"language":76},[74],"$ mkdir ~\u002F.ssh\n$ chmod 700 ~\u002F.ssh \n",[28,6832,6830],{"__ignoreMap":79},[13,6834,6835,6837,6838,6840],{},[28,6836,6810],{},"は権限を700にしましょう。そうで無いと権限エラーによってdevelopに対するsshを行うことができません。そしてクライアントから転送された公開側の名前を変更して",[28,6839,6810],{},"配下に置いておきます。",[71,6842,6845],{"className":6843,"code":6844,"language":76},[74],"$ cp ~\u002Fid_rsa.pub ~\u002F.ssh\u002Fauthorized_keys\n$ chmod 600 ~\u002F.ssh\u002Fauthorized_keys\n$ rm ~\u002Fid_rsa.pub\n",[28,6846,6844],{"__ignoreMap":79},[13,6848,6849,6850,6853],{},"ここでも",[28,6851,6852],{},"authorized_keys","は600権限を付けないと使用できません。",[1224,6855,6857,6860,6867],{"className":6856},[1227,1228],[13,6858,6859],{},"authorized_keysにリネームする理由",[13,6861,6862,6863,1864],{},"The authorized_keys file in SSH specifies the SSH keys that can be used for logging into the user account for which the file is configured.(",[196,6864,6866],{"target":1232,"href":6865},"https:\u002F\u002Fwww.ssh.com\u002Facademy\u002Fssh\u002Fauthorized-keys-file#:~:text=The%20authorized_keys%20file%20in%20SSH,keys%20and%20needs%20proper%20management.","参照",[13,6868,6869],{},"authorized_keysファイルはその公開鍵に紐づく秘密鍵を用いてログインできるユーザーを特定します。簡単な話、authorized_keysにしておけばsshが自動的に鍵を判別してくれるのでその名前にしておく。",[13,6871,6872],{},"これでdevelopは鍵認証を用いてログインできる様になりました。",[33,6874,6875],{"id":6875},"rootのリモートログインとパスワード認証を禁止にする",[13,6877,6878,6879,6882],{},"developで鍵認証で接続できることを確認したら次はrootのリモートログインとパスワード認証を禁止にします。",[28,6880,6881],{},"\u002Fetc\u002Fssh\u002Fsshd_config","を編集していきます。",[71,6884,6887],{"className":6885,"code":6886,"language":76},[74],"# vi \u002Fetc\u002Fssh\u002Fsshd_config\n\n---------- 以下行を追加 -----------\nPermitRootLogin no\n---------- 以上行を追加 -----------\n\n--------------以下を変更--------------\nPasswordAuthentication yes\n#RSAAuthentication yes\n#PubkeyAuthentication yes\n--------------↓--------------\nPasswordAuthentication no\nRSAAuthentication yes\nPubkeyAuthentication yes\n------------------------------------------\n",[28,6888,6886],{"__ignoreMap":79},[13,6890,6891,6894,6895,6898,6899,6902,6903,6906],{},[28,6892,6893],{},"PermitRootLogin no","という記述をつけます。名の通りルートのログインを禁止にさせました。そして",[28,6896,6897],{},"PasswordAuthentication no","としパスワード認証を禁止。",[28,6900,6901],{},"RSAAuthentication yes","と",[28,6904,6905],{},"PubkeyAuthentication yes","のコメントアウトを外して鍵認証のみでつなげる様に明示的に設定します。",[13,6908,6909],{},"これであとはsshdをリスタートさせれば反映させます。",[71,6911,6914],{"className":6912,"code":6913,"language":76},[74],"# systemctl restart sshd\n",[28,6915,6913],{"__ignoreMap":79},[13,6917,6918],{},"試しにチェックしましょう。",[71,6920,6923],{"className":6921,"code":6922,"language":76},[74],"ssh root@xxx.xxx.xxx\nroot@xxx.xxx.xxx: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).\n\nssh develop@xxx.xxx.xxx\ndevelop@xxx.xxx.xxx: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).\n",[28,6924,6922],{"__ignoreMap":79},[13,6926,6927],{},"OKです。逆にdevelopで鍵認証で接続したのに弾かれたら設定をミスっています。",[1224,6929,6932],{"className":6930},[1227,6931],"alert-danger","\n接続系を設定するときは2つのターミナルタブを開いていておき、片方はずっとroot化できる状態でサーバーにログインしておき、片方で接続テストをしましょう。もし失敗してどのユーザー・方法でも接続できなくなると二度とサーバーに接続できなくなります。\n",[33,6934,6935],{"id":6935},"sshの接続ポートを変更する",[13,6937,6938],{},"sshはデフォルトで22のポートで接続します。しかしこのポートはwell-knownポートとして知られており、攻撃者もデフォルトのポートを狙ってきます。そこでsshのポートを変更してさらに攻撃されにくくします。sshに接続するためにはユーザー名、鍵・パスワード、ポートが合わないといけないからです。",[13,6940,6941],{},"まずはsshdのデフォルトポートを変更します。変更するポート番号は49513～65535あたりから自由に設定しましょう。",[71,6943,6946],{"className":6944,"code":6945,"language":76},[74],"# vi \u002Fetc\u002Fssh\u002Fsshd_config\n--------------以下を変更--------------\n#Port 22    \n--------------↓--------------\nPort 49510\n------------------------------------------\n",[28,6947,6945],{"__ignoreMap":79},[13,6949,6950],{},"そしてfirewallが有効な場合、sshによる22は許可していてもカスタムしたポートは許可していないことがあります。これではカスタムポートへ接続する前にfirewallで弾かれるので設定します。",[13,6952,6953],{},"まずはsshdのfirewallの設定ファイルをコピーします。",[71,6955,6958],{"className":6956,"code":6957,"language":76},[74],"cp \u002Fusr\u002Flib\u002Ffirewalld\u002Fservices\u002Fssh.xml \u002Fetc\u002Ffirewalld\u002Fservices\u002F\n",[28,6959,6957],{"__ignoreMap":79},[13,6961,6962,6965,6966,6969],{},[28,6963,6964],{},"\u002Fetc\u002Ffirewalld\u002Fservices\u002F","にて追加の設定を行うことができます。コピーした",[28,6967,6968],{},"ssh.xml","を編集します。",[71,6971,6974],{"className":6972,"code":6973,"language":76},[74],"# vi \u002Fetc\u002Ffirewalld\u002Fservices\u002F\n\u003C?xml version=\"1.0\" encoding=\"utf-8\"?>\n  \u003Cservice>\n    \u003Cshort>SSH\u003C\u002Fshort>\n    \u003Cdescription>Secure Shell (SSH) is a protocol ...\u003C\u002Fdescription>\n    \u003Cport protocol=\"tcp\" port=\"22\"\u002F>\n    \u003Cport protocol=\"tcp\" port=\"49510\"\u002F> # 追加\n\u003C\u002Fservice>\n",[28,6975,6973],{"__ignoreMap":79},[13,6977,6978],{},"上記の設定でsshサービスによる49510ポートの接続が許可されました。\nそして設定が終わったらfirewallをリロードします。またsshdも設定を変えたのでリロードします。",[71,6980,6983],{"className":6981,"code":6982,"language":76},[74],"# firewall-cmd --reload\n# systemctl restart sshd\n",[28,6984,6982],{"__ignoreMap":79},[13,6986,6987],{},"これでOKです。ポートをカスタムのものに指定して接続して通れば問題ありません。そして22（デフォルト）で接続して弾かれるかも確認しましょう。",[17,6989,6991],{"id":6990},"以上","以上！",[13,6993,6994],{},"以上がsshの最低限必要な設定です。インフラ系では結構基礎的な内容だそうです。sshは狙われており、適切に設定することで安全に使用することができます。",{"title":79,"searchDepth":113,"depth":113,"links":6996},[6997,6998,7006],{"id":6641,"depth":107,"text":6642},{"id":6668,"depth":107,"text":6668,"children":6999},[7000,7003,7004,7005],{"id":6688,"depth":113,"text":6688,"children":7001},[7002],{"id":6752,"depth":119,"text":6752},{"id":6783,"depth":113,"text":6783},{"id":6875,"depth":113,"text":6875},{"id":6935,"depth":113,"text":6935},{"id":6990,"depth":107,"text":6991},[342],"2021-04-25",{},"\u002Farticles\u002Fvps-ssh-first",{"title":6597,"description":6597},"articles\u002Fvps-ssh-first",[7014,2856,354],"security","_mix\u002Fcyber-security-3400657_640.jpg","0p7STSITYfCR0ETcCcYcMeNhmXEtc_cRA-W1MKHcN_8",1780987141951]