.htaccessにページ単位での301リダイレクトを効率よく記述する。

新しいサイトを作ったので、旧サイトのコンテンツをサブドメインにお引越ししたいという状況になりました。
その場合はリダイレクト設定をしないと検索エンジンにそっぽを向かれてしまう恐れがあります。

301リダイレクトにはドメイン単位とかディリクトリ単位とかいろいろあります。

今回のケースだとページごとにひとつずつ設定するしかなさそうだったので、やった手順を書き残しておきます。

はじめに

サーバーはApacheです。いろいろ試した結果、私の環境では以下のコードできちんとリダイレクトできました。

RewriteEngine on
RewriteRule ^before.html$ https://ecco.co.jp/after.html [L,R=301]

引用元:https://ecco.co.jp/blog/htaccess-redirect/

※このとき気づいたのが、日本語URLはエンコードされているとリダイレクトしないので、デコードしておく必要がありました。

作業手順

設定が必要なURLを収集

  1. Screaming Frog SEO Spiderを使い対象ページを収集。
  2. 収集したURLをCSV形式でダウンロードし、Googleスプレッドシードにアップ。
  3. フォーマットに沿った形に文字列を連結する。
  4. .htaccessに転記してアップ。実際の挙動を確認。

(1)Screaming Frog SEO Spiderを使い、サイトの全ページを取得し、投稿ページのみリダイレクト対象としてCSVファイルにエクスポートしました。


Screaming Frog SEO Spider とは?

海外製のアプリで、サイトをクロールしSEOに必要な各種データを取得できる便利なツールです。

(2)Googleスプレッドシードにアップし、不要なデータを削除。リダイレクト先のURL一覧を作ります。

(3)フォーマットに沿った形になるように文字列を連結します。(画像参照)
ScreamingFrogSEO Spiderのスクリーンショット

(4)コードが完成したら、.htaccessに記載しサーバーにアップ。
ブラウザからアクセスし、正しくリダイレクトできているか確認。

以上です!

【JavaScript 復習】querySelector()とclassListを使ってclassを着脱するサンプル

実装したサンプル

タイトルの通り、JavaScriptのquerySelector()classListを使い、DOM要素にclassをつけたり外したりするスクリプトのサンプルを作ってみました。

See the Pen
class attach test
by kouichi hoshi (@kouichi_hoshi)
on CodePen.

querySelector()

引数で渡した値にマッチするhtml要素の最初のひとつを取得します。
HTMLElementが返されます。

const foo = document.querySelector("p");
const bar = document.querySelector("#id");
const baz = document.querySelector(".class");
const bee = document.querySelector("div.user-panel.main input[name='login']");

querySelectorAll()

マッチする全ての要素を取得したい場合はdocument.querySelectorAll()を使います。
NodeListが返却されます。

const all = document.querySelectorAll("p");

jQueryライクに記述できて便利です。

classList

document.querySelector("p").classList.add("red");

のように記述すると、取得したhtml要素に対して引数で渡した値をclassとして付与することができます。

document.querySelector("p").classList.remove("red");

のように記述すると、引数の値にマッチするclassを除去します。

document.querySelector("p").classList.contains("red");

classの有無を判定し、真偽値を返します。

document.querySelector("p").classList.toggle("red");

とし、クリックイベントなどで発火させればclassの着脱が可能。

IEを気にすることはほとんど無くなったし、jQuery無しのDOM操作が面倒だった時代は終わったのかもしれませんね。

参考サイト

JavaScript classListでクラス属性を操作するゾ – かもメモ

【2019年6月】Node.js/npm-scriptsでWordPressのテーマ開発環境を構築。(ライブリロードあり)

WordPressのテーマ作成用のGulp開発環境をしばらく放置してしまい、gulpと各種プラグイン、Node.js本体をバージョンアップしたところエラーが多発してビルドできない状況になってしまいました。

これを機に、以前からやってみたかったnpm-scriptsによるビルド環境に移行することにしました。本記事は、その時実施した内容の備忘録です。

実装した機能

  • PHPファイル、画像ファイル、npm管理外のプラグイン/ライブラリファイル等をsrcからdistにコピー
  • テーマファイルを削除
  • sassのコンパイル(ワイルドカードも可)
  • cssにベンダープレフィックス付与
  • JavaScriptをES5に変換してバンドル(rollup.js使用)
  • JS/CSSをフォーマット(prettier使用)
  • ファイルを監視→WPのテーマディリクトリに出力→ライブリロード
ご注意

※本記事はMacで検証しています。package.jsonのconfigの値を参照する記法がwindowsの場合は異なるという情報がありますが、未検証なのでご注意ください。

※WordPressのローカル環境構築は割愛しています。あらかじめdistディリクトリに設置し、起動できる前提としています。筆者はMAMPを使っています。

※ライブリロードは、WordPressを動作させるローカルサーバー(この記事ではMAMP)をbrowser-syncで連携させることにより利用できる前提です。

ディリクトリ構成

theme-dev/
 ├ dist/ *WordPressを設置
 ├ src/
  ├ package.json
  ├ rollup.config.js *rollup.jsの設定ファイル
  ├ bs-config.js *browser-syncの設定ファイル
  ├ php/ *WordPressのテーマで使うphpファイルはここにまとめて設置。
  ├ public/ *npmで配布されていないライブラリなどはここに設置。
  ├ images/
  └ assets/
    ├ js/
    └ sass/

一式まとめた圧縮ファイルはこちら

package.json作成

$ npm init

パッケージのインストール

ファイルのコピー/削除

$ npm install cpx --save-dev
$ npm install rimraf --save-dev

sassコンパイル/sassワイルドカード

$ npm install node-sass --save-dev
$ npm install node-sass-globbing --save-dev

ベンダープレフィックス追加

$ npm install postcss-cli autoprefixer --save-dev

JS ES5変換/バンドル

$ npm install rollup --save-dev
$ npm install rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-babel --save-dev
$ npm install @babel/core @babel/preset-env --save-dev

コードフォーマッタ

$ npm install prettier --save-dev

スクリプトの直列/並列実行

$ npm install npm-run-all --save-dev

ファイル監視/ライブリロード

$ npm install watch --save-dev
$ npm install browser-sync --save-dev

設定ファイルの作成

ルートディリクトリに下記設定ファイルを設置。

rollup.config.js

import resolve  from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel  from 'rollup-plugin-babel';

export default {
  input: 'src/assets/js/script.js',
  output: {
    format: 'iife',
    dir: 'dist/wp-content/themes/theme-dev' //テーマファイルを出力したいパスを指定
  },
  plugins: [
    resolve({
      jsnext: true
    }),
    commonjs(),
    babel({
      presets: [
        [
          "@babel/preset-env", {
          "modules": false,
          "targets": {
            "browsers": ['last 2 versions']
          }
        }
        ]
      ],
      babelrc: false
    })
  ],
  experimentalCodeSplitting: true
};

bs-config.js

※MAMP等でサーバーを起動したときにWordPressサイトが動作するURLをproxyに記載します。

module.exports = {
    "proxy": "http://localhost:8888/theme-dev/dist/" //MAMP等のローカルサーバーを指定
};

package.jsonにnpm-scriptsを追加

※configとscriptsのみ掲載します。
※distPathはテーマファイルを出力したいパスを指定します。

  "config": {
    "distPath": "/dist/wp-content/themes/theme-dev",
    "sassIndex": "/src/assets/sass/style.scss"
  },
  "scripts": {
    "clean": "rimraf .$npm_package_config_distPath",
    "copy/php": "cpx 'src/php/**/*.php' .$npm_package_config_distPath",
    "copy/public": "cpx 'src/public/**/*' .$npm_package_config_distPath/public",
    "copy/image": "cpx src/images/*/ .$npm_package_config_distPath/images",
    "copy": "npm-run-all -p copy/*",
    "css/sass": "node-sass --importer node_modules/node-sass-globbing/index.js .$npm_package_config_sassIndex -o .$npm_package_config_distPath --output-style expanded --source-map .$npm_package_config_distPath",
    "css": "npm-run-all -s css/*",
    "js/rollup": "rollup -c=rollup.config.js",
    "js": "npm-run-all -s js/*",
    "fmt/js": "prettier --write src/assets/js/*.js",
    "fmt/sass": "prettier --write src/assets/sass/**/*.scss",
    "fmt": "npm-run-all -p fmt/*",
    "build": "npm-run-all -s clean copy/* css js fmt",
    "dev/server": "browser-sync start --config bs-config.js --files=.$npm_package_config_distPath/*.css, .$npm_package_config_distPath/*.js, .$npm_package_config_distPath/**/*.php",
    "dev/css": "watch 'npm run css' src/assets/sass/",
    "dev/js": "watch 'npm run js' src/assets/js/",
    "dev/php": "watch 'npm run copy' src/php/",
    "dev/image": "watch 'npm run copy' src/images/",
    "dev/fmt": "watch 'npm run fmt' src/assets/js/ src/assets/sass/**/",
    "dev": "npm-run-all -p build dev/*",
    "prd/sass": "node-sass --importer node_modules/node-sass-globbing/index.js .$npm_package_config_sassIndex -o .$npm_package_config_distPath --output-style expanded",
    "prd/postcss": "postcss .$npm_package_config_distPath/style.css -o .$npm_package_config_distPath/style.css",
    "prd": "npm-run-all -p prd/*",
    "release": "npm-run-all -s clean copy prd js fmt"
  },


※configのdistPathにはテーマファイルを出力したいパスを指定します。

使用できるコマンド

開発用ビルド

$ npm run build

開発用ライブリロード

$ npm run dev


※このコマンドでエラーが起きる場合はいったんnpm run buildしてみてください。

本番用ビルド

$ npm run release

PHPファイル、画像ファイル、任意のプラグイン/ライブラリファイル等をsrcからdistにコピー

$ npm run copy

テーマファイルを丸ごと削除

$ npm run clean

まとめ

CSS/JSの圧縮は今回見送りました。webpackを使うと良いのかもしれません。

また、lint系のプラグインも入れてません。この辺はエディタ任せでもいいかと思いつつ、気が向いたら試すかなー?という感じです。

Local by Flywheelとの連携も試しました。browser-syncの監視対象をカンマ区切りで複数指定すると、ファイルを編集してないのに勝手にリロードするという現象が発生しましたが、カンマ区切りやめてアスタリスクで全ファイル指定したら大丈夫そうでした。


以下の記事を参考にさせていただきました。(ありがとうございました)

【2019年5月】 Nuxt.jsインストールとカスタマイズ。(webサイト構築用)

最近Nuxt.jsを使ってサイト制作をちょこちょこやってます。なかなか楽しい。
自分なりの環境構築の手順と、追加の設定をまとめておきます。

開発環境

MacOS 10.14.4
Node.js v12.2.0

Nuxt.jsをインストール

任意のディリクトリで下記コマンドを実行する。

npm init nuxt-app <project-name>

参考:インストール – Nuxt.js

Nuxt.jsをカスタマイズ

Sassをコンパイル可能にする

コンパイラとローダーを追加する。

npm install --save-dev node-sass sass-loader

 

foundationなcssを設置

サイト全体で効かせたい共通デフォルトのcssはfoundation.scssに書きたい。
foundation.scssを作成し、nuxt.config.jsに以下のように追記

export default {
  css: [
    '@/assets/scss/foundation.scss'// プロジェクト内のSCSSファイル
  ]
}

ress(リセットCSS)をインストール

リセットCSSにressを採用。下記コマンドでインストール。

npm install --save ress

nuxt.config.jsに以下のように追記。

export default {
  css: [
    'ress',// Node.js モジュールをロードする
  ]
}

各コンポーネントで共通のsass変数やmixinを使えるようにする

style-resources-moduleプラグインを使って実現する。
下記コマンドでインストール。

yarn add @nuxtjs/style-resources

variables.scss、mixin.scssを作成し、nuxt.config.jsに以下のように追記

modules: ['@nuxtjs/style-resources'],
styleResources: {
  scss: [
    '@/assets/scss/variables.scss',
    '@/assets/scss/mixin.scss'
  ]
}

参考:《Nuxt.js》Sassの共通の変数やmixinを一括で各コンポーネントに読み込む方法。 – Qiita

アプリケーションの起動

サーバーを起動し、nuxtサイトを表示させる

npm run dev

上記コマンドを実行しブラウザでhttp://localhost:3000にアクセスする。
ファイル監視、ホットリロードも動作する。

デプロイ

静的ファイルを生成する

下記コマンドで静的なファイルが生成できる。

npm run generate

その他

コンポーネントごとにCSSにスコープをつける

<style scooped>

Laravel(LaravelMix)でCSS GridをIE11に対応しやすくするAutoprefixerの設定。

こちらの記事でAutoprefixerを使用してCSS GridをIE11に対応させる方法が紹介されています。

上記の記事ではgulpやwebpackでの実装方法が書かれているのですが、LaravelMixでどうやるかは書かれていなかったので調べてみました。

前提条件

Laravel本体のインストールとnpm installが済んでいる状態。Laravelのバージョンは5.7.7で試しました。
Autoprefixerはデフォルトで使用可能になっています。

実装

webpack.mix.jsに、以下のコードを追記する。

mix.options({
    postCss: [
        require('autoprefixer')({
            grid: true // ←tureでIE11対応のベンダープレフィックスが出力される
        })
    ]
});
/*これが*/
.container {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 50px 1fr 50px;
}
/*こうなる*/
.container {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: 200px 1fr;
      grid-template-columns: 200px 1fr;
  -ms-grid-rows: 50px 1fr 50px;
      grid-template-rows: 50px 1fr 50px;
}

参考:Autoprefixerが進化してCSS GridのIE 11対応がバリ楽になった(2017年〜2018年)
Laravel Mix & Autoprefixer

追記

//こんな書き方でコンパイルできる。
mix.js('resources/js/app.js', 'public/js');
mix.sass('resources/sass/app.scss', 'public/css');
mix.options({
    postCss: [
        require('autoprefixer')({
            browsers: ['last 2 versions'],
            grid: true
        })
    ]
});

//これもOK。
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css')
    .options({
        postCss: [
            require('autoprefixer')({
                browsers: ['last 2 versions'],
                grid: true
            })
        ]
    });

pointer-events: none;が効かない。Edge + a要素 + display:inline;の組み合わせは要注意。

pointer-events: none;は要素にマウスやタッチで触ることができなくなるCSSのプロパティです。

最近よく使うようになったのですが、Edgeでうまく動作しないケースに遭遇し、何でだーとなったので記録を残しておきます。

原因

原因はEdgeのpointer-events: none;の実装にあるようです。

a要素にpointer-events: none; とdisplay:inline;を同時に適用すると、pointer-events: none;が機能しなくなります。Edgeのバグではないかと思われます。

対策

displayをinline以外の値に変えてやると正常に機能します。

以下に確認用のサンプルを作成しました。Edgeだとpointer-events: none;が動作せずa要素がクリック(タップ)できてしまい、アラートが出るようにスクリプトを入れてあります。

以上に挙げた条件以外でも期待通りの動作をしないケースがあるようです。以下の記事が参考になります。

CSS pointer-events 2016 – dskd