@import '~module/dist/x.css' を含む vue cli project (module) を Nuxt で読み込むには?

以下に従って、Vue CLI 3 から npm package を 2 つ作成しました。

A1 … <h1> を含む component
B1 … 上記 component A1 を表示する component

それぞれ vue create で作成した Project を編集・追加したものです。
component で使っている css は js から分離して出力されるようにしています。

そして、

  • component A1 の css を B1 で読み込む
  • component B1 の css を Nuxt で読み込む

と順次 css ファイルを読み込み、装飾に使っています。

B1A1 の css を読み込む時、

@import '~a1/dist/A1.esm.css';

のように path の先頭に tilde (~) を付けなければ正しく読み込んでくれません。

でも、Nuxt では node_modules 内の css フィアルを読み込む際、tilde (~) を付けるとエラーが出ます。

Nuxt から B1 の css を読み込むと、B1 css ファイル内で A1 css への path に tilde (~) が含まれてしまうため、エラーが出てしまいます。

tilde を消して package building を行えば Nuxt で使う際もエラーは出なくなりますが、tilde を消したり付けたりする手作業が発生します。

tilde を付けたり消したりせずに、package 単体時と Nuxt での使用時の両方でエラーを抑える方法はないでしょうか?


具体的に示します。

まずは component A1 を下図に示します。

(1) A1.scss … A1 に適用する css。font color のみ設定。
(2) A1.vue … component A1
(3) App.vue … A1 を表示するための component

これを yarn serve でブラウザーに表示させると以下のようになります。

20190513T052049

続いて、component B1 を下図に示します。

(4) B1.scss … B1 に適用する css。background color のみ設定。
(5) A1.esm.css … A1 で用いた css。tilde (~) を付けて指定。
(6) B1.vue … compnent B1
(7) App.vue … B1 を表示するための component

これを yarn serve でブラウザーに表示させると以下のようになります。

20190513T052638

最後に、component B1 を使う Nuxt を下図に示します。

(8) B1.esm.css … B1 に適用した css。
(9) B1 を使用

これを yarn dev でブラウザーに表示させると以下のエラーが出ます。

ERROR  in ./pages/index.vue?vue&type=style&index=0&lang=scss&               

Module build failed (from ./node_modules/postcss-loader/src/index.js):       
Error: Can't resolve '~a1/dist/A1.esm.css' in 'C:/.../css_loader.b1/dist'

 at onError                  (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/Resolver.js:61:15)                                           
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
 at runAfter                 (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/Resolver.js:158:4)                                          
 at innerCallback            (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/Resolver.js:146:3)                                     
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
 at next                     (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/node_modules/tapable/lib/Tapable.js:252:11)                         
 at innerCallback            (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/Resolver.js:144:11)                                    
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
 at next                     (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/node_modules/tapable/lib/Tapable.js:249:35)                         
 at resolver.doResolve.createInnerCallback (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:44:6)
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
 at afterInnerCallback       (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/Resolver.js:166:11)                               
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
 at next                     (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/node_modules/tapable/lib/Tapable.js:249:35)                         
 at C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/ModuleKindPlugin.js:23:4                                              
 at loggingCallbackWrapper   (C:/.../css_loader.nuxt/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)                 
                                                                             
 @ ./node_modules/vue-style-loader??ref--9-oneOf-1-0!
   ./node_modules/css-loader/dist/cjs.js??ref--9-oneOf-1-1!
   ./node_modules/vue-loader/lib/loaders/stylePostLoader.js!
   ./node_modules/postcss-loader/src??ref--9-oneOf-1-2!
   ./node_modules/sass-loader/lib/loader.js??ref--9-oneOf-1-3!
   ./node_modules/vue-loader/lib??vue-loader-options!
   ./pages/index.vue?vue&type=style&index=0&lang=scss& 4:14-369 14:3-18:5 15:22-377

 @ ./pages/index.vue?vue&type=style&index=0&lang=scss&
 @ ./pages/index.vue
 @ ./.nuxt/router.js
 @ ./.nuxt/index.js
 @ ./.nuxt/client.js
 @ multi eventsource-polyfill webpack-hot-middleware/client?reload=true&timeout=30000&ansiColors=&overlayStyles=&name=client&path=/__webpack_hmr/client ./.nuxt/client.js

これを修正するため、下記 B1.vue@import (10) において

a

以下のように書き換えます。

(前) @import '~a1/dist/A1.esm.css'; ...................... (a)
(後) @import 'a1/dist/A1.esm.css';

~a1tilde (~) を消します。

その結果、以下のように Nuxt 上で <B1> を表示できます。

20190513T055222

webpack では、node_modules 内の css を import する際、上記 (a) のように tilde を付けるのですが、Nuxt で使う時は (a) の tilde は不要となります。

Vue CLI で作成した Project を単体で扱うこともあるので、(a) の tilde を付けたり消したりするのは面倒です。

変更することなく、統一できる方法をご存知の方いらっしゃいませんか?

もしくは、そもそも vue cli で作った vue component の npm package としての使い方が間違っていて、こういう風に使うといい、という忠告でも構いません。

source を調べてみたところ、下図の通り、tilde(~) を含むのが前提の処理だったので、vue.config.js 内の option でどうにかできるものではないようです。

node_modules/loader-utils/lib/urlToRequest.js

というわけで、以下のような PostCSS plugin を作成して、

  • Vue CLI project 内では tilde(~) を付けずに @import を記述
  • plugin 内で tilde(~) を後付け

としてみました。
# postcss は不慣れなので間違ってたら指摘お願いします

postcss-tilde-module.js

const postcss = require('postcss')
const not_allowed = './~'; ................................ (1)

module.exports = postcss.plugin('tilde-module', opts => {
  return (root, result) => {
    root.nodes.forEach(node => {
      if (node.name == 'import') {
        const params = node.params.replace(/["']/g, '');
        const char0 = params[0];

        if (! not_allowed.includes(char0)) {
          node.params = `"~${params}"`;
        }
      }
    })

    return root;
  }
})

postcss.config.js

const tilde = require('./postcss-tilde-module')();

module.exports = (ctx) => ({
  plugins: [
    tilde,
  ]
});

(1) で設定している ./~ は、

  • 相対パス (.)や絶対パス (/) の場合
  • tilde(~) で始まっている場合

を除くために使っています。
もしかしたら ./ は不要かもしれません。

以上で、error 無く yarn serve が通るようになりました。

a

20190515T131331

間違いや他の方法がありましたら指摘と教授お願いします。