vuejs / vue-loader

📦 Webpack loader for Vue.js components
MIT License
4.99k stars 915 forks source link

vue loader 17.0.0 + Vue3 + <script setup> + typescript = confused imports/exports error #1955

Open Colisan opened 2 years ago

Colisan commented 2 years ago

Version

16.8.3

Reproduction link

github.com

Steps to reproduce

Hi, I encounter the following, very puzzling, build&runtime error :

index.ts

import { createApp } from "vue";
import test from "./test.ce.vue";

console.log("imported");
console.log("imported", test);

export const toto = "toto";

createApp(test).mount(document.body);

test.ce.vue

<script setup lang="ts">
    import { toto } from './index';

    const greeting= 'Hello ' + toto + ' !';
</script>

<template>
  <p class="greeting">{{ greeting }}</p>
</template>

<style>
.greeting {
  color: red;
  font-weight: bold;
}
</style>

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");

module.exports = {
  entry: './src/index.ts',
  mode: "production",
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.tsx?$/,
        use: [{loader: 'ts-loader', options: {onlyCompileBundledFiles: true}}],
      },
      {
        test: /\.jsx?$/,
        use: [
          {
            loader: "babel-loader",
          },
        ],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          "sass-loader",
        ],
      },
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          "css-loader",
        ],
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      title: "MAIN UI",
      scriptLoading: "module",
      template: "src/index.ejs",
      filename: "index.html",
    }),
  ],
};

tsconfig.json

{
    "compilerOptions": {
      "outDir": "./dist/",
      "noImplicitAny": true,
      "module": "es2020",
      "target": "es5",
      "jsx": "preserve",
      "allowJs": true,
      "moduleResolution": "node"
    }
  }

What is expected?

No error

What is actually happening?

WARNING in ./src/test.ce.vue?vue&type=script&setup=true&lang=ts 1:0-205
export 'default' (reexported as 'default') was not found in '-!../node_modules/ts-loader/index.js??clonedRuleSet-1.use[0]!../node_modules/vue-loader/dist/index.js??ruleSet[1].rules[8].use[0]!./test.ce.vue?vue&type=script&setup=true&lang=ts' (possible exports: toto)
 @ ./src/test.ce.vue 1:0-69 2:0-64 2:0-64 7:49-55
 @ ./src/index.ts 2:0-33 4:24-28 6:10-14

When building, somehow the loader think that the exports from the vue file are instead the exports from the index.ts file. The same happen in another big project where the .vue export seems to be confused from any random exports in any random .ts file. It's not only a type warning, the actual imported object at runtime is wrong too!

Maybe there's a conflit between vue-loader and ts-loader? Maybe my configuration is wrong?


Workaround

If I replace the script with a non-Typescript one:

<script setup>
    import { toto } from './index';

    const greeting= 'Hello ' + toto + ' !';
</script>

It works fine and without error. However, not using Ts is not an option in my context and I'd prefer if we could fix the causes instead of dodging the consequences =)

mjbradvica commented 2 years ago

Having this issue as well.

jbruwes commented 2 years ago

You probably should use appendTsSuffixTo: [/\.vue$/] in the ts-loader to avoid the problem.

{
 test: /\.tsx?$/,
 loader: "ts-loader",
 options: {
  appendTsSuffixTo: [/\.vue$/]
 },
 exclude: /node_modules/,
},
{
 test: /\.vue$/i,
 loader: "vue-loader",
 options: {
  esModule: true,
 },
},
Colisan commented 2 years ago

@jbruwes Well found! It indeed solve the problem.

Maybe we should add this critical information somewhere in the vue-loader documentation?

jbruwes commented 2 years ago

There is a mention in the documentation related to the issue: https://github.com/TypeStrong/ts-loader#appendtssuffixto

Just as it has been written in the documentation: "This is useful for *.vue file format for now. (Probably will benefit from the new single file format in the future.)"

mjbradvica commented 2 years ago

Um, no this is a bug. The @vue/cli-plugin-babel broke this going from V4.5 to ~V5.0 for re-exporting components.