Open d-akara opened 6 years ago
Vue files currently does not support type exports, because that's processed at the TypeScript checker level, and all *.vue
modules are simply shimmed to be of type Vue
(see your vue-shims.d.ts
). I don't think this can be fixed in vue-loader
unless we have first-class *.vue
support in TS itself.
/cc @octref
@yyx990803 I forgot to mention, webpack will build properly on incremental build. So after the error is shown on initial build, if you then just touch the file InlineMessage.vue
it will then build without error.
I don't understand enough of the internal build process to know if this is useful information or not, but just wanted to point it out in case.
An unrelated opinion: I think we should put the below code in a separate ts file. because it's purely model mode.
export type MessageType = 'none' | 'info' | 'warning' | 'error' | 'success' | 'loading'
export interface Message {
type: MessageType
dismissable: boolean
content: string
}
and I prefer declare a enum type for MessageType
, such as:
export enum MessageType{
none = 'none',
info = 'info' ,
warning = 'warning',
error = 'success' ,
loading = 'loading',
}
As @yyx990803 said there is no existing way to do this. Your best bet right now would be having a type.ts
file where you define the types and import them from the Vue files.
@DanielRosenwasser Do you know what would it take to have this supported in TS? https://github.com/Microsoft/TypeScript/issues/12846 doesn't seem to cover it.
Really, you need something special to resolve these types correctly within
There's always been a problem with importing from .vue
files from a .ts
file in the language service (i.e. in the editor)
I've forgotten whether the Webpack loaders are capable of doing "the right thing" without the vue-shims.d.ts
file.
Could this way help you ?
//index.ts
import Test from "./Test.vue";
export default Test;
You can just write your template and styles in .vue file (and it is surport scoped
scss
less
) ,and script in ts files;
//Template.vue
<template>
<div>Test</div>
</template>
<style lang="scss" scoped>
</style>
//test.ts
import { Vue, Component, Prop } from "vue-property-decorator";
import _Template from "./Template.vue";
@Component({
mixins: [_Template],
})
export default class Test extends Vue {
public id: string = "Test";
}
//in ohter .ts to import
import Test from "@/Test"
expport default TestChild extend Test{
console.info(this.id);
}
You can use ts type now; You can also use tsx like react; It is surport ts type;
@yyx990803 @dakaraphi
@nailfar yes, it has been worked around using .ts files. It is just not as convenient.
We can write a bash or node script to create module files.
run command such as npm run generate app/views/test.
then create the Test.ts , Index.ts and Template.vue files with templates in app/views/test;
// ts Template
import { Vue, Component, Prop } from "vue-property-decorator";
( other common import you want here);
import _Template from "./Template.vue";
@Component({
mixins: [_Template],
})
export default class {{FILE_NAME}} extends Vue {
public id: string = "{{FILE_NAME}}";
(do some thing others you want...)
}
// vue Template
<template>
<div class="module-{{FILE_NAME}}">{{FILE_NAME}}</div>
</template>
<style lang="scss" scoped>
</style>
// barrel Template
import {{FILE_NAME}} from "./{{FILE_NAME}}.vue";
export default {{FILE_NAME}};
{{FILE_NAME}} will be replaced by the script; one command many code;
@nailfar This will make the hot update not work
This is the two methods I tried, but there are still problems. https://github.com/TypeStrong/ts-loader/issues/826
And a another way:
Type conversion of vue components with additional ts
files.
file list
Hello.vue // <script src="./Hello.script.ts"></script>
Hello.script.ts // <script> content
Hello.ts // magic wrap
Hello.ts
content
import components from './Hello.vue';
import componentsClass from './Hello.script';
class Magic extends componentsClass {}
(<any>Magic) = components;
export default Magic;
This is written using vue-class-component
.
@yyx990803 It is probably a good idea to allow vue-loader to use the ts file as an entry point.
about webpack.module.rules
We can use double extensions to avoid affecting normal ts files. For example *.vue.ts
(I have been exploring vue + typescript and if there is a chance I hope we can talk about it.)
I found a more appropriate method. (https://github.com/TypeStrong/ts-loader/issues/826#issuecomment-416828492)
We only need to spoof the IDE's language service to achieve the goal. For example:
Demonstrates Repository: https://github.com/ZSkycat/issue-ts-loader-20180829/tree/better
Hello.vue
<template>
<div><h1>Hello</h1></div>
</template>
<script src="./Hello.vue.ts"></script>
Hello.vue.ts
import { Component, Vue } from 'vue-property-decorator';
@Component<Hello>({
name: 'Hello',
})
export default class Hello extends Vue {
hello() {
console.log('hello!');
}
}
Used in ts file
import Hello from './Hello.vue';
The most important thing is the naming of the ts file.
@dakaraphi
The real problem is that you should not reexport type here. Exporting type in vue file is fine.
More technical detail: Vue loader depends on ts-loader to transpile script. And ts-loader in turn requires vue-loader to extract script from vue file. Communication between two loaders are done via webpack: vue-loader will generate script files like app.vue.ts
in webpack and ts-loader will read those files.
At first build, vue-loader hasn't generated script. To kick off the generation, vue-loader has to first ask ts-loader for script content to find out all components in the build. Thus, ts-loader transpiles script independently without other files' info in the first run because vue files aren't processed yet. But in later build type checking works because script generation has done before.
However, re-exporting type requires type info and cannot be transpiled solely by one single file.
My recommendation is to turn on --isolateModules
flag in tsconfig, which bans re-exporting type and guarantees successful transpilation. Transpilation itself is essential in large app since it speeds up build, and it is also assumed by lots of other tools. For example, babel, thread-loader and fork-ts-checker-plugin all exploit TS's transpilation feature to some extent. isolateModules
is also recommended officially. https://blogs.msdn.microsoft.com/typescript/2018/08/27/typescript-and-babel-7/
As @yyx990803 said, vue-loader cannot do much here. So this issue can be safely closed since exporting type actually works . Supporting re-exporting type isn't widely supported in JS community and I suspect its value.
There is a workaround with default objects. // types.ts
// Type intended to share between vue components
type MyCommonType = {
id?:string,
name:string,
}
export const MyDefaultProp:MyCommonType = {
id:'',
name:'',
}
// component1.vue
. . .
import {MyDefaultProp} from './types.ts'
type MyPropType = typeof MyDefaultProp // Better than defining whole type/interface
export default class Component1 extends Vue {
@Prop({ default: () => Object.assign({}, MyDefaultProp), type: Object }) myProp!: MyPropType
. . .
// component2.vue
. . .
import {MyDefaultProp} from './types.ts'
type MyPropType = typeof MyDefaultProp // Better than defining whole type/interface
export default class Component2 extends Vue {
@Prop({ default: () => Object.assign({}, MyDefaultProp), type: Object }) myProp!: MyPropType
. . .
Typescript compiler will be happy without any warning...
I am gonna import ts file in vue component. But the following error happens.
Githubissues.
Version
15.0.0
Reproduction link
https://github.com/dakaraphi/vue-loader-bug-sample
Steps to reproduce
1) clone referenced github repo. 2) npm install 3) npm run build
What is expected?
Should build without error
What is actually happening?
16:77-84 "export 'Message' was not found in './InlineMessage.vue'
This seems related to https://github.com/vuejs/vue-loader/issues/1234