vue-loader + TypeScriptの「Module not found: Error: Can't resolve './listToStyles'」エラー

# モチベーション

- jsだけで構築されたChrome Extensionを作成したい（index.html無しで）
- `*.js` は一切書かず、 `*.ts` `*.vue` だけ書きたい（webpack.configもTypeScript）

# ハマったところ

`*.vue` ファイルの `<style>` タグがscssだとコンパイルが通らなかった

```vue:a.vue
<style lang='scss'>
```

```
ERROR in ./node_modules/vue-style-loader/lib/addStylesClient.js 7:0-41
Module not found: Error: Can't resolve './listToStyles' in 'path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib'
```

とか

```
Field 'browser' doesn't contain a valid alias configuration
```

とかエラーが出て[調べた](https://www.google.com/search?q=Field+%27browser%27+doesn%27t+contain+a+valid+alias+configuration+site%3Agithub.com&rlz=1C5GCEA_enJP959JP959&oq=Field+%27browser%27+doesn%27t+contain+a+valid+alias+configuration+site%3Agithub.com&aqs=chrome..69i57.5425j0j7&sourceid=chrome&ie=UTF-8)が、何もピンと来るソリューションが見当たらなかった人に、ぜひ良い助けになってほしい。

<details>
<div>

```
$ yarn webpack
yarn run v1.22.11
$ path/to/webpack-error-reproduction/node_modules/.bin/webpack
asset index.bundle.js 34.5 KiB [emitted] (name: index)
runtime modules 937 bytes 4 modules
modules by path ./src/ 4.79 KiB
  ./src/index.ts 297 bytes [built] [code generated]
  ./src/a.vue 1.16 KiB [built] [code generated]
  ./src/a.vue?vue&type=template&id=45c6ab58&scoped=true& 205 bytes [built] [code generated]
  ./src/a.vue?vue&type=script&lang=ts& 314 bytes [built] [code generated]
  ./src/a.vue?vue&type=style&index=0&id=45c6ab58&lang=scss&scoped=true& 322 bytes [built] [code generated]
  ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/a.vue?vue&type=template&id=45c6ab58&scoped=true& 212 bytes [built] [code generated]
  ./node_modules/ts-loader/index.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/a.vue?vue&type=script&lang=ts& 297 bytes [built] [code generated]
  ./node_modules/vue-style-loader/index.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/a.vue?vue&type=style&index=0&id=45c6ab58&lang=scss&scoped=true& 1.68 KiB [built] [code generated]
  ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/a.vue?vue&type=style&index=0&id=45c6ab58&lang=scss&scoped=true& 352 bytes [built] [code generated]
modules by path ./node_modules/ 10.4 KiB
  ./node_modules/vue-loader/lib/runtime/componentNormalizer.js 2.71 KiB [built] [code generated]
  ./node_modules/vue-style-loader/lib/addStylesClient.js 6.09 KiB [built] [code generated]
  ./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]

ERROR in ./node_modules/vue-style-loader/lib/addStylesClient.js 7:0-41
Module not found: Error: Can't resolve './listToStyles' in 'path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib'
resolve './listToStyles' in 'path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib'
  using description file: path/to/webpack-error-reproduction/node_modules/vue-style-loader/package.json (relative path: ./lib)
    Field 'browser' doesn't contain a valid alias configuration
    using description file: path/to/webpack-error-reproduction/node_modules/vue-style-loader/package.json (relative path: ./lib/listToStyles)
      no extension
        Field 'browser' doesn't contain a valid alias configuration
        path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib/listToStyles doesn't exist
      .vue
        Field 'browser' doesn't contain a valid alias configuration
        path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib/listToStyles.vue doesn't exist
      .ts
        Field 'browser' doesn't contain a valid alias configuration
        path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib/listToStyles.ts doesn't exist
      as directory
        path/to/webpack-error-reproduction/node_modules/vue-style-loader/lib/listToStyles doesn't exist
 @ ./node_modules/vue-style-loader/index.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/a.vue?vue&type=style&index=0&id=45c6ab58&lang=scss&scoped=true& 9:10-85
 @ ./src/a.vue?vue&type=style&index=0&id=45c6ab58&lang=scss&scoped=true& 1:0-322 1:0-322
 @ ./src/a.vue 4:0-86
 @ ./src/index.ts 6:30-48

webpack 5.53.0 compiled with 1 error in 934 ms
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

</div>
</details>

# 再現状況

https://github.com/nogahighland/webpack-error-reproduction

ファイル構成はこんな感じ。

```
▾ src/
    a.vue
    index.ts
    sfc.d.ts
  package.json
  tsconfig.json
  webpack.config.ts
  yarn.lock
```

```json:package.json
{
  "name": "test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "css-loader": "^6.2.0",
    "node-sass": "^6.0.1",
    "sass-loader": "^12.1.0",
    "ts-loader": "^9.2.5",
    "ts-node": "^10.2.1",
    "typescript": "^4.4.3",
    "vue-loader": "^15.9.8",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^5.53.0",
    "webpack-cli": "^4.8.0"
  },
  "volta": {
    "node": "14.17.6",
    "yarn": "1.22.11"
  },
  "dependencies": {
    "vue": "^2.6.14"
  }
}

```

```ts
import path from 'path'
import { VueLoaderPlugin }  from 'vue-loader'

export default {
  mode: 'development',

  entry: {
    index: path.join(__dirname, 'src', 'index.ts')
  },

  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.pug/,
        loader: 'pug-plain-loader'
      },
      {
        test: /\.scss$/,
        use: ['vue-style-loader', 'css-loader', 'sass-loader']
      }
    ]
  },

  plugins: [
    new VueLoaderPlugin()
  ],

  resolve: {
    extensions: ['.vue', '.ts', '.js'] // .js が無いと「Module not found: Error: Can't resolve './listToStyles'」エラー
  }
}
```

中身はごくごく単純で、エントリーポイントとなる src/index.ts から src/a.vue を読み込ませ、コンパイル & バンドルした上で dist/index.bundle.js として吐き出すというもの。lintしたり `vue-property-decorator` を入れたり `vuex` を入れたりといった余計な設定は極限まで削ぎ落としている。

```ts:src/index.ts
import A from './a.vue'
console.log(A)
```

```vue:src/a.vue
<template>
</template>

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({

})
</script>

<style lang='scss' scoped>
div {
  background-color: #000
}
</style>

```

# 修正方法

上記に書いてあるままなのだが、webpackのコンパイルターゲットの拡張子に `.js` を加えるだけだった。

```diff
  resolve: {
-    extensions: ['.vue', '.ts']
+    extensions: ['.vue', '.ts', '.js']
  }
```

# 結論に至るまでの試行錯誤集

- webpack.config **.ts** が悪さをしているのか？
- webpack.config.ts の `exclude` に `/node_modules/` が無いからいけないのか？
- `entries` に設定するファイルの拡張子が `.js` じゃないとダメなのか？
- `vue-loader` の設定が悪いのか？
- `vue-loader` のバージョンが悪いのか？
- `ts-loader` がダメなのか？ `vue-loader` との相性が悪いのか？
- `ts-loader` じゃなくて `babel-loader` なら良いのか？

記録に残せないほどいろいろ試行錯誤してやっとたどり着けたが、正直なところなんで `.js` を足せば動くのかよく分からない。
一つ言えるのは絶対にTypeScriptしか書かないという強い意志が無ければここまでたどり着けなかった。