Nuxt.js で開発していると、Sass ( Scss ) 変数を管理するファイルを作成し、@nuxtjs/style-resources ライブラリを使って、各コンポーネントから参照することが多いかと思います。
// @/assets/scss/_consts.scss
$COLOR_PRIMARY: #4aac00;
$COLOR_SECONDARY: #0f83fd;
<!-- @/components/Test.vue -->
<template>
<div class="Test">
<p class="Test_Text">Text1</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'Test'
})
</script>
<style lang="scss" scoped>
.Test_Text {
color: $COLOR_PRIMARY;
}
</style>
こんな感じで。
この Sass ( Scss ) 変数を Vue コンポーネントの <template>
内や、<script>
内でも使いたい!
( JavaScript と CSS で変数を共有したい! )
手順
1、:export
を定義する
// @/assets/scss/_consts.scss
$COLOR_PRIMARY: #4aac00;
$COLOR_SECONDARY: #0f83fd;
+ :export {
+ COLOR_PRIMARY: $COLOR_PRIMARY;
+ COLOR_SECONDARY: $COLOR_SECONDARY
+ }
:export
で Vue コンポーネントから参照したい変数を定義する。
2、Vue コンポーネントで使う
<!-- @/components/Test.vue -->
<template>
<div class="Test">
<p class="Test_Text">Text1</p>
+ <p :style="styleObj">Text2</p>
+ <p :style="{ color: COLOR_SECONDARY }">Text3</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
+ import colorModule from '@/assets/scss/_consts.scss';
export default Vue.extend({
+ name: 'Test', // ←カンマ追加しただけ
+ data () {
+ return {
+ COLOR_SECONDARY: colorModule.COLOR_SECONDARY
+ }
+ },
+ computed: {
+ styleObj () {
+ return {
+ color: this.COLOR_SECONDARY
+ }
+ }
+ }
})
</script>
<style lang="scss" scoped>
.Test_Text {
color: $COLOR_PRIMARY;
}
</style>
import colorModule from '@/assets/scss/_consts.scss';
で scss ファイルをインポートします。
そして、colorModule.COLOR_PRIMARY
や colorModule.COLOR_SECONDARY
とすることで、先ほど :export {}
内に定義した変数にアクセスできます。
3、エラーの解消
stylelint を使っている場合
stylelint
を使っているプロジェクトであれば、このようなエラーが出ているのではないでしょうか?
assets/scss/_consts.scss
5:1 ✖ Unexpected unknown pseudo-class selector ":export" selector-pseudo-class-no-unknown
6:3 ✖ Unexpected unknown property "COLOR_PRIMARY" property-no-unknown
7:3 ✖ Unexpected unknown property "COLOR_SECONDARY" property-no-unknown
これを解消するために、ルールを追加します。
// stylelint.config.js
module.exports = {
extends: [
'stylelint-config-standard',
'stylelint-config-prettier'
],
rules: {
'selector-pseudo-class-no-unknown': [
true,
{ 'ignorePseudoClasses': ['export'] }
],
'property-no-unknown': [
true,
{ 'ignoreProperties': ['/^COLOR_/'] }
]
}
}
-
selector-pseudo-class-no-unknown
に、:export
という疑似クラスの使用を許可するルールを追加 -
property-no-unknown
に、正規表現でCOLOR_
から始まるプロパティの使用を許可するルールを追加
TypeScript を使っている場合
TypeScript
を使っているプロジェクトであれば、このようなエラーが出ているのではないでしょうか?
ERROR ERROR in components/Test.vue:12:25 12:35:18
TS2307: Cannot find module '@/assets/scss/_consts.scss' or its corresponding type declarations.
10 | <script lang="ts">
11 | import Vue from 'vue'
> 12 | import colorModule from '@/assets/scss/_consts.scss';
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13 | export default Vue.extend({
14 | name: 'Test',
15 | data () {
これを解消するために、型定義ファイルを作成します。
// @/types/scss.d.ts
declare module '*.scss';
番外編
ここまでで、Sass ( Scss ) 変数が vue ファイルの <template>
内や <script>
内で使えるようになったかと思います。
が、:export {}
を定義したファイル内で Sass の math 機能 を使ったときに、このようなエラーが出ているのではないでしょうか?
Module build failed (from ./node_modules/sass-loader/dist/cjs.js): friendly-errors 12:43:45
SassError: @use rules must be written before any other rules.
╷
14 │ @use "sass:math";
│ ^^^^^^^^^^^^^^^^
╵
これを解消するために、export: {}
部分のみを別ファイルに切り出します。
// @/assets/scss/constsForJs.scss
:export {
COLOR_PRIMARY: $COLOR_PRIMARY;
COLOR_SECONDARY: $COLOR_SECONDARY
}
<!-- @/components/Test.vue -->
<template>
<div class="Test">
<p class="Test_Text">Text1</p>
<p :style="styleObj">Text2</p>
<p :style="{ color: COLOR_SECONDARY }">Text3</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
+ import colorModule from '@/assets/scss/constsForJs.scss';
export default Vue.extend({
name: 'Test',
data () {
return {
COLOR_SECONDARY: colorModule.COLOR_SECONDARY
}
},
computed: {
styleObj () {
return {
color: this.COLOR_SECONDARY
}
}
}
})
</script>
<style lang="scss" scoped>
.Test_Text {
color: $COLOR_PRIMARY;
}
</style>
まとめ
今回は、Nuxt.js ( Vue.js ) を例に挙げましたが、Next.js ( React ) や、UI ライブラリを使っていない場合でも同じ手法が使えます。
:export
で 変数を定義し、sass ( scss ) ファイルを import
する。
そして、必要であれば stylelint
にルールを追加や型定義ファイルを追加するだけ。