Vue.jsを使い始めていろいろできることが多くなってきたので、整理する意味も兼ねてチュートリアルにまとめます。
今回はコーポレートサイトを想定して作成していきます。
※記事が長くなったのでチュートリアルを分割しました。
目次
前提
- タスクは
npm scripts
で一限管理 - コマンドは
yarn
を使用 -
vue-cli
のwebpack-simple
を使用 - CSSは
SCSS
を使用し用途に合わせてPostCSS
を使用
バージョン
- "vue": "^2.5.11"
- "webpack": "^3.6.0"
- "node-sass": "^4.7.2"
- "postcss": "^6.0.16"
- "stylelint": "^8.4.0"
CSSの環境構築
SassとPostCSSを使用するので以下のコマンドでパッケージを追加します。
※今回はautoprefixerでPostcSSの動作確認をおこないます。
$ yarn add -D node-sass postcss postcss-loader autoprefixer
PostCSSの設定ファイルを追加します。
module.exports = (ctx) => ({
plugins: [
require('autoprefixer')
]
});
webpackの設定ファイルを修正します。
var path = require('path')
var webpack = require('webpack')
module.exports = {
// 省略
module: {
rules: [
// 省略
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
'scss': [
'vue-style-loader',
'css-loader',
'postcss-loader', // ← 追加
'sass-loader'
],
// 省略
Index.scssとAbout.scssで動作確認用のスタイルを記述します。
.block {
color: red;
display: flex;
}
.block {
color: blue;
display: flex;
}
ブラウザでindexとaboutをそれぞれ確認し、開発ツールでdisplayがプレフィックスがついていて、それぞれ赤文字、青文字になっていたら成功です。
ちなみに、前回vueファイル側でstyle部分にscoped
を記述していました。
<template
lang="pug"
src="./Index.pug"
/>
<script src="./Index.js" />
<style
lang="scss"
src="./Index.scss"
scoped
/>
ページ単位では上書きされないようにローカルなスタイルにする意味でscoped
を記述していました。
上書きさせたい場合、scoped
を記述しなければ通常の記述になります。
参考:スコープ付き CSS
グローバルなCSSの環境構築
上記のCSSの設定はvueコンポーネントごとの個別用で使用し、全体で使用するスタイルは別で用意します。
※reset.css, normarize.css, 各共通コンポーネント等です。
CSSディレクトリを作成し、CSS設計をおこないます(以下は参考)
/src
/css
/base
_variable.scss
_mixin.scss
_function.scss
_base.scss
/components
_typography.scss
_button.scss
_icon.scss
_form.scss
_table.scss
/modules
_header.scss
_footer.scss
/layouts
_container.scss
/templates
_temp-list.scss
_temp-article.scss
/vendor
_normarize.scss
style.sscss
/layouts
Default.vue
/pages
Index.vue
Hoge.vue
App.vue
main.js
router.js
index.html
その他設定ファイル等
cssファイルを読み込む記述を追加します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-skeleton</title>
<link rel="stylesheet" href="/css/style.css"> <!-- ← 追加 -->
</head>
<body>
<div id="app"></div>
<script src="/js/bundle.js"></script>
</body>
</html>
normalize.scssをダウンロードして以下に格納します。
/src/css/vendor/
グローバルなSCSSはwebpackとは別で監視したほうがwebpackに依存しなくて良いので、node-sassを使って監視します。
{
// 省略
"scripts": {
"watch:server": "browser-sync start --config bs-config.js",
"watch:file": "cpx \"./src/**/{*.html,*.jpg,*.png,*.gif,*.svg,*.eot,*.ttf,*.woff,package.json}\" ./dist",
// ↓ 追加
"watch:css": "node-sass src/css/style.scss dist/css/style.css -w --source-map true",
// ↑ 追加
"watch:js": "webpack -w",
"start": "run-p watch:*",
// 省略
},
// 省略
}
vue-body-classの追加
CSS設計をおこなう際に、ページごとにスタイルをテンプレートとして出し分けたい場合があります。
そんな時にbodyにページごとのclassを振って出し分けるのですが、vue-routerはrouter-view
部分の差分変更をおこなうので、基本的にはbodyの操作をしないようになっていると思います。
そんな時にrouter-viewでpathの変更ごとにbodyのclass設定をおこなえるようにしたのがvue-body-classです。
さっそく追加しましょう。
$ yarn add vue-body-class
main.jsに追記しましょう。
この時、Vue.use(BodyClass, router)
はconst router = ...
の後に記述しないときちんと反応しないので気をつけましょう。
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Routes from './router.js'
import BodyClass from 'vue-body-class' // ← 追記
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes: Routes
})
Vue.use(BodyClass, router) // ← 追記
const app = new Vue({
router,
render:h => h(App)
}).$mount('#app');
次にrouter.jsに実際に各ページに付与するclass名を追記していきましょう。
export default [
{
path: '/',
name: '',
component: require('./layouts/Default.vue').default,
children: [
{
path: '',
name: 'index',
meta: { bodyClass: 'page-index' }, // ← 追記
component: require('./pages/Index/Index.vue').default,
},
{
path: '/about/',
name: 'about',
meta: { bodyClass: 'page-about' }, // ← 追記
component: require('./pages/About/About.vue').default
},
{
path: '/service/',
name: 'service',
meta: { bodyClass: 'page-service' }, // ← 追記
component: require('./pages/Service/Service.vue').default
},
{
path: '/recruite/',
name: 'recruite',
meta: { bodyClass: 'page-recruite' }, // ← 追記
component: require('./pages/Recruite/Recruite.vue').default
},
{
path: '/contact/',
name: 'contact',
meta: { bodyClass: 'page-contact' }, // ← 追記
component: require('./pages/Contact/Contact.vue').default
}
]
}
]
ブラウザで確認してページごとにbodyのclassが変更されていれば成功です。
ちなみに、親で付与したclassを子に引き継いだり上書きしたり、ということもできます。
詳しくは公式ドキュメントを参考にしてください。
stylelintの設定
グローバルなCSSとwebpack環境下のCSS両方にstylelintを設定します。
パッケージを追加します。
yarn add -D stylelint stylelint-webpack-plugin
stylelintの設定ファイルを用意します。
今回は以下を/srcに格納します。
エディタで監視する設定をおこないます。
以下を参考におこなってみてください。
グローバルなCSS
他所から持ってきたSCSSファイルにstylelintを反応させたくないので、.stylelintignoreを/src直下に作成して以下を記述します。
/src/css/vendor/**/*.scss
/src/cssのscssファイルでエラーや警告表示になる記述をして、stylelintがエディタで反応したら成功です。
webpack環境下のCSS
webpackの設定ファイルに追記します。
// 省略
var StylelintPlugin = require('stylelint-webpack-plugin')
module.exports = {
// 省略
plugins: [
new StylelintPlugin({
files: ['**/*.vue', '**/*.scss']
})
],
// 省略
}
参考:A nice way to lint .vue
files with Stylelint? #303
Index.vueやAbout.scssでstylelintがエディタで反応していたら成功です。
エラー・警告が出ている場所を確認して修正しましょう。
postcss-sortingの追加
プロパティ順をソートできるようにしましょう。
以下の記事を参考に導入しましょう。scssファイルでもいけます。
参考:PostCSS SortingでCSSの@ルールやプロパティの記述順を整理
まとめ
CSSは設定しやすくハンドリングが難しいので、設計がとても大事です。
scopedはどれに適用させるのか、共通コンポーネントのスタイルはどこに書くべきか、等の判断も必要になってくるかと思います。
全体を俯瞰し、破綻しにくく運用しやすい設計を意識すると良いでしょう。