matsuo_basho
@matsuo_basho

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

webpack5 で .vueがコンパイルできず困っています。

いつもお世話になっております。
表題について質問です。

先ほどwebpack5の環境で.vueをコンパイルできるように環境を整えていたのですが
トライアンドエラーの末、改善せず行き詰まっております。
どなたか解決法がわかる方がいらっしゃればご教授いただけると幸いです。

環境

・webpack : 5.32.0
・webpack-cli : 4.6.0
・vue-loader : 15.9.6
・vue-template-compiler : 2.6.12

発生している問題・エラー

[webpack-cli] Failed to load '/Users/hode/aaa/webpack.prod.js' config
[webpack-cli] TypeError: VueLoaderPlugin is not a constructor
    at Object.<anonymous> (/Users/hode/aaa/webpack.common.js:134:5)
    at Module._compile (/Users/hode/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (/Users/hode/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at Object.<anonymous> (/Users/hode/aaa/webpack.prod.js:4:22)
    at Module._compile (/Users/hode/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)

該当するソースコード

package.json
{
        "name": "frontend",
        "version": "1.0.0",
        "main": "index.js",
        "license": "MIT",
        "scripts": {
                "dev": "gulp Pug:Serve & webpack serve --config webpack.dev.js",
                "build": "gulp Pug:Build & webpack --config webpack.prod.js",
        },
        "devDependencies": {
                "@babel/cli": "^7.13.14",
                "@babel/core": "^7.13.15",
                "@babel/preset-env": "^7.13.15",
                "@babel/preset-flow": "^7.13.13",
                "autoprefixer": "^10.2.5",
                "babel-eslint": "^10.1.0",
                "babel-loader": "^8.2.2",
                "css-loader": "^5.2.1",
                "css-minimizer-webpack-plugin": "^2.0.0",
                "csscomb-loader": "^0.0.2",
                "eslint": "^7.24.0",
                "eslint-config-airbnb": "^18.2.1",
                "eslint-import-resolver-webpack": "^0.13.0",
                "eslint-loader": "^4.0.2",
                "eslint-plugin-flowtype": "^5.7.0",
                "eslint-plugin-import": "^2.22.1",
                "eslint-plugin-jsx-a11y": "^6.4.1",
                "eslint-plugin-react": "^7.23.2",
                "eslint-plugin-react-hooks": "^4",
                "flow-bin": "^0.148.0",
                "gulp": "^4.0.2",
                "gulp-notify": "^3.2.0",
                "gulp-plumber": "^1.2.1",
                "gulp-pug": "^4.0.1",
                "gulp-sass": "^4.1.0",
                "html-webpack-plugin": "^5.3.1",
                "mini-css-extract-plugin": "^1.4.1",
                "node-sass-package-importer": "^5.3.2",
                "postcss-loader": "^5.2.0",
                "postcss-sort-media-queries": "^3.8.9",
                "prettier": "^2.2.1",
                "pug": "^3.0.2",
                "pug-plain-loader": "^1.1.0",
                "sass": "^1.32.8",
                "sass-loader": "^11.0.1",
                "style-loader": "^2.0.0",
                "terser-webpack-plugin": "^5.1.1",
                "ts-loader": "^8.1.0",
                "typescript": "^4.2.4",
                "vue-loader": "^15.9.6",
                "vue-template-compiler": "^2.6.12",
                "webpack": "^5.32.0",
                "webpack-cli": "^4.6.0",
                "webpack-dev-server": "^3.11.2",
                "webpack-merge": "^5.7.3",
        },
        "dependencies": {
                "destyle.css": "^2.0.2",
                "react": "^17.0.2",
                "react-dom": "^17.0.2",
                "vue": "^2.6.12"
        }
}

webpack.common.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const { VueLoaderPlugin } = require('vue-loader/lib/plugin-webpack5');

/* ----- パス設定 ----- */
const path = require('path');

const dir = {
  src: path.join(__dirname, 'src'),
  dist: path.join(__dirname, 'dist'),
};

/* ----- js rules ----- */
const jsRules = {

  // *----- js | lint -----*
  jsLint: {
    test: /\.(ts|js|vue)$/,
    exclude: /node_modules/,

    // ビルド前に構文チェック
    enforce: 'pre',
    loader: 'eslint-loader',
    options: {

      // 構文エラーがあった場合はfixする
      fix: true,

    },
  },

  // *----- js | compile -----*
  jsCompile: {
    test: /\.(ts|js|vue)$/,
    exclude: /node_modules/,
    loader: 'babel-loader',
  },

};

/* ----- css rules ----- */
const cssRules = {

  // *----- css, scss, sass | compile -----*
  test: /\.(scss|sass|css)$/,
  exclude: /node_modules/,
  use: [

    MiniCssExtractPlugin.loader,
    'vue-style-loader',
    {
      // css を js にバンドル
      loader: 'css-loader',
      options: {

        // オプションでCSS内のurl()メソッドの取り込みを禁止する
        url: false,

        // 0 => no loaders (default);
        // 1 => postcss-loader;
        // 2 => postcss-loader, sass-loader
        importLoaders: 2,

      },
    },

    'csscomb-loader',
    'postcss-loader',
    'sass-loader',

  ],

};

/* ----- 設定 ----- */
module.exports = {

  entry: {

    main: path.resolve(dir.src, 'js/main.js'),
    sub: path.resolve(dir.src, 'js/sub.js'),
    style: path.resolve(dir.src, 'scss/index.scss'),

  },

  output: {

    // 生成先のディレクトリ
    path: dir.dist,

    // 生成されるファイル名( 出力されるのをbundle )
    filename: '[name].bundle.js',

  },

  resolve: {

    // import文のパス指定に node_modules を省略できるようにする
    modules: ['node_modules'],

    // 拡張子を省略できるようにする
    extensions: ['.ts', '.js', '.vue'],

    alias: {
      vue: 'vue/dist/vue.esm.js',
    },

  },

  module: {
    rules: [
      jsRules.jsLint,
      jsRules.jsCompile,
      cssRules,
    ],
  },

  plugins: [

    new MiniCssExtractPlugin({
      filename: '[name].bundle.css',
    }),

    new RemoveEmptyScriptsPlugin(),

    new VueLoaderPlugin(),

  ],

};

webpack.prod.js
const { merge } = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const commonConfig = require('./webpack.common');

module.exports = merge(commonConfig, {

  mode: 'production',

  optimization: {

    splitChunks: {

      cacheGroups: {

        vendor: {
          chunks: 'initial',
          test: /node_modules/,
          name: 'vendor',
        },

      },
    },

    minimizer: [

      new CssMinimizerPlugin(),

      new TerserPlugin({
        extractComments: false,
        terserOptions: {

          output: {
            comments: false,
            beautify: false,
          },

          compress: {
            drop_console: true,
          },

        },
      }),

    ],

  },

});

自分で試したこと

https://qiita.com/7110/items/0721525ed6ccc263768b に記述されている内容を試してみましたが改善せず。

0

8Answer

vue-loader/lib/plugin-webpack5 からインポートする場合は

const { VueLoaderPlugin } = require('vue-loader/lib/plugin-webpack5');

ではなく

const VueLoaderPlugin = require('vue-loader/lib/plugin-webpack5');

にしてください。エクスポート側が module.exports = VueLoaderPlugin になっているからです。 https://github.com/vuejs/vue-loader/blob/b53ae44e4b9958db290f5918248071e9d2445d38/lib/plugin-webpack5.js#L210

また、わざわざ vue-loader/lib/plugin-webpack5 を参照しなくても以下のようにインポートすれば webpack のバージョンに合ったプラグインが自動で選ばれます。

const { VueLoaderPlugin } = require('vue-loader');
1Like

Comments

  1. @matsuo_basho

    Questioner

    ああ、、「質問者コメント」ではマークダウンが表示されないのですね。
    一旦最初のコメントは削除します。

vue-loader からインポートするなら波括弧ありの const { VueLoaderPlugin } = require('vue-loader') が正しい書き方です。その場合に出る

Error: [VueLoaderPlugin Error] No matching use for vue-loader is found. Make sure the rule matching .vue files include vue-loader in its use.

は、 vue-loader を使うルールがないせいです。 rules

      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },

を追加してください。参考: https://vue-loader.vuejs.org/guide/#manual-setup

1Like

どうやら拡張子 .vue にマッチする最初のルール(enforce 設定があるルールを除く)で vue-loader を使わないとエラーになるようです。( https://github.com/vuejs/vue-loader/blob/b53ae44e4b9958db290f5918248071e9d2445d38/lib/plugin-webpack5.js#L46 あたりを参照)

webpack.common.js では jsCompile ルールが先にマッチするためエラーになっています。先ほどの設定を残したまま

   jsCompile: {
-    test: /\.(ts|js|vue)$/,
+    test: /\.(ts|js)$/,
     exclude: /node_modules/,
     loader: 'babel-loader',
   },

とするか、設定を消して

   jsCompile: {
-    test: /\.(ts|js|vue)$/,
+    test: /\.(ts|js)$/,
     exclude: /node_modules/,
-    loader: 'babel-loader',
+    use: ['babel-loader', 'vue-loader'],
   },
 

とすると動きました。前の回答でリンクしたガイドを見る限り、 vue-loader は Babel を必要としないので前者がよさそうです。

1Like

vue-style-loader の README によれば

this is included as a dependency and used by default in vue-loader, in most cases you don't need to configure this loader yourself.

とのことなので設定が重複していそうですね。そもそも MiniCssExtractPlugin と (vue-)style-loader はどちらか一方を使うものですから消して大丈夫です。

1Like

@uasiさん

最後までご丁寧にお付き合いいただきありがとうございます!

本っっっっ当に助かりました!!

1Like

@uasiさん

早速のご回答ありがとうございます!
Qiitaで質問してみたのが初めてだったので、返ってくるのかが心配でしたが回答をいただけて安心しました。

アドバイス通りに、

const { VueLoaderPlugin } = require('vue-loader');

const VueLoaderPlugin = require('vue-loader');

をそれぞれ試してみたのですが、
エラーの内容が変わっただけで、エラー自体は解消されないようでした。

const { VueLoaderPlugin } = require('vue-loader');

で行った場合のエラー内容です。

[webpack-cli] Error: [VueLoaderPlugin Error] No matching use for vue-loader is found.
Make sure the rule matching .vue files include vue-loader in its use.
    at VueLoaderPlugin.apply (/Users/hoge/aaa/node_modules/vue-loader/lib/plugin-webpack5.js:93:13)
    at createCompiler (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:74:12)
    at create (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:123:16)
    at webpack (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:131:47)
    at WebpackCLI.f [as webpack] (/Users/hoge/aaa/node_modules/webpack/lib/index.js:54:15)
    at WebpackCLI.createCompiler (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1845:29)
    at async WebpackCLI.buildCommand (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1952:20)
    at async Command.<anonymous> (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:742:25)
    at async Promise.all (index 1)
    at async Command.<anonymous> (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1289:13)
const VueLoaderPlugin = require('vue-loader');

で行った場合のエラー内容です。

[webpack-cli] Failed to load '/Users/hoge/aaa/webpack.prod.js' config
[webpack-cli] TypeError: loaderContext.emitError is not a function
    at new module.exports (/Users/hoge/aaa/node_modules/vue-loader/lib/index.js:36:19)
    at Object.<anonymous> (/Users/hoge/aaa/webpack.common.js:134:5)
    at Module._compile (/Users/hoge/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (/Users/hoge/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at Object.<anonymous> (/Users/hoge/aaa/webpack.prod.js:4:22)
    at Module._compile (/Users/hoge/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (/Users/hoge/aaa/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at loadConfig (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1327:31)

webpack.common.jsconst VueLoaderPlugin = require('vue-loader');がなければ、
ちゃんとwebpack.prod.jsも読み込まれるので、
結局はvue-loaderが悪さをしているんだろうなと思うのですが、、。

0Like

@uasiさん

早速のご回答ありがとうございます!
(ご丁寧にリンクも貼っていただきありがとうございます。)

まず、vue-loaderのインポート法は
const { VueLoaderPlugin } = require('vue-loader')に固定しました。

その上で、rules

module: {
    rules: [
      jsRules.jsLint,
      jsRules.jsCompile,
      cssRules,
      
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+      },

    ],
  },

を追加しましたが、
以下のエラーが発生し変わらず解消しないようです。

[webpack-cli] Error: [VueLoaderPlugin Error] No matching use for vue-loader is found.
Make sure the rule matching .vue files include vue-loader in its use.
    at VueLoaderPlugin.apply (/Users/hoge/aaa/node_modules/vue-loader/lib/plugin-webpack5.js:93:13)
    at createCompiler (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:74:12)
    at create (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:123:16)
    at webpack (/Users/hoge/aaa/node_modules/webpack/lib/webpack.js:131:47)
    at WebpackCLI.f [as webpack] (/Users/hoge/aaa/node_modules/webpack/lib/index.js:54:15)
    at WebpackCLI.createCompiler (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1845:29)
    at async WebpackCLI.buildCommand (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1952:20)
    at async Command.<anonymous> (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:742:25)
    at async Promise.all (index 1)
    at async Command.<anonymous> (/Users/hoge/aaa/node_modules/webpack-cli/lib/webpack-cli.js:1289:13)

う〜ん、node_modulesを再インストールしてみても変わらないのですが、
完全に行き詰まってしまいましたね、、。

0Like

@uasiさん

本当にありがとうございました。
無事に解決しコンパイルができるようになりました。
素晴らしいです、、。

ちなみに、これまで webpack.common.jshttps://ics.media/entry/16028/ を参考に vue-style-loader を追加していたのですが、
vue-style-loaderを追加するとエラーが発生するようでした。
(逆にコメントアウトするとコンパイルができます)

調べたところ、htmlにインラインでcssを挿入するためのstyle-loaderから派生したものらしく、
自分はインラインでcssを挿入しないようにしているので、
この場合はvue-style-loaderを削除してしまっても大丈夫でしょうか?

恐らく大丈夫だろうと思うのですが、念の為確認をさせていただけますと幸いです。
(こちらの確認をもって最後の質問とさせいていただければと思います、、!)

0Like

Your answer might help someone💌