structure of the project

webpack.config.js
module.exports = {
entry: './src/js/app.js',
output: {
path: 'dist/',
filename: './js/bundle.js'
},
module: {
loaders: [
{
test: /\.tsx?$/,
loader: 'ts-loader'
},
{
test: /\.vue$/,
loader: 'vue'
}
]
}
}
app.ts
declare var require;
declare var Vue;
new Vue({
el: 'body',
components: {
'nani': require('../components/nani.vue')
}
})
nani.vue
<template><p>纳尼?你再说一次.</p></template>
<script lang="ts">
export = {
methods: {
sayHello: function () {
alert('hello')
}
}
</script>
each time I run webpack, it always report this error,
$ webpack ‹ruby-2.1.4›
ts-loader: Using [email protected]
Hash: 54f28de48a69455dfb02
Version: webpack 1.12.9
Time: 1239ms
Asset Size Chunks Chunk Names
./js/bundle.js 2.74 kB 0 [emitted] main
[0] ./src/js/app.js 178 bytes {0} [built]
+ 4 hidden modules
ERROR in ./~/ts-loader!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/nani.vue
Module build failed: Error: Could not find file: '/Users/tcstory/WebstormProjects/test/src/components/nani.vue'.
at getValidSourceFile (/Users/tcstory/WebstormProjects/test/node_modules/typescript/lib/typescript.js:43586:23)
at Object.getEmitOutput (/Users/tcstory/WebstormProjects/test/node_modules/typescript/lib/typescript.js:46680:30)
at Object.loader (/Users/tcstory/WebstormProjects/test/node_modules/ts-loader/index.js:410:34)
@ ./src/components/nani.vue 2:17-111
how to solve this problem?
visit the link to see the project
https://github.com/tcstory/vue-loader-test
Interestingly this is because ts-loader is a big hack and is not a in-memory transform (i.e. it relies on actual files on disk), so it can't work with *.vue files... I don't think there's an easy way to make this work, unless someone who knows more about TypeScript can figure out why ts-loader is implemented that way.
On another look, you may need to set the transpileOnly flag to true: https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
:) thanks
I too, have tried to setup a TS environment using vue components (I love the idea that it is based on, its small site, and the goal to keep it that way), and while using vue in a plain ts file setup is not a big problem (you can even user nice decorators) , the vue files is a problem as stated above.
Further more, the editor support for the vue files is a problem too, as some kind of .d.ts file are missing too.
It would be nice if the vue-loader could optionally write a ts (or a d.ts) file in the same path as the vue component. This would fix the above problem, but more importantly it would make better IDE support too, as the tsc now knows the components types too.
Do you think this problem could be solved by the shorthand ambient module declarations proposal ?
Hey @yyx990803 can you elaborate a little on the problems? I'm not that familiar with Webpack's internals, but it looks like TypeScript is being fed the .vue file itself. I don't necessarily know why that would occur, since we don't try to resolve plain calls to require AFAIK.
just to clarify, will ts hot-reload with non-*.vue files?
i.e: with vue-typescript ?
in this case, vue-loader wouldn't be used at all.
I have managed to get vuex to hot-reload with typescript, but the UI does'nt reload
thanks
You can make vue-loader work with TS, if you put ts code in separate file.
myComponent.vue:
<template>
...
</template>
<style>
...
</style>
<script lang="ts" src="./myComponent.vue.ts"></script>
myComponent.vue.ts:
TS code goes here
You can use both 'ts' and 'awesome-typescript' loaders, just override ts lang option in vue-loader settings.
Sample usage here:
https://github.com/yegor-sytnyk/contoso-express/ branch alt/vue
@DanielRosenwasser It seems vue-loader will transform .vue file into JavaScript, where content <script> tag will be transformed into seome require call like
require("!!ts!./../../node_modules/vue-loader/lib/selector.js?type=script&index=0!./nani.vue")
Mind the selector.js in the middle. It comes from vue-loader and extract content in the script tag of a vue file. Then selector.js feed the extracted content to callback, which calls ts-loader defined here.
Here comes the problem. ts-loader do compile file by using filePath, not content. vue-loader feeds to ts-loader file path like *.vue rather than *.ts. TSC rejects vue file and ignores extracted content.
From what I understand of Webpack, sounds like if vue-loader was able to know to create a .ts intermediate file, things would "just work", but I could be wrong.
I found as long as the filename ends with .ts, typescript will compile. ts-loader has already used a languageService so no intermediate file is needed. I could be wrong because I haven't tested multiple files but from reading the source I guess it would work.
If anyone is still interested in using TypeScript in *.vue, vue-ts-loader is a choice to have a look.
@HerringtonDarkholme what changes are there between vue-ts-loader and ts-loader? It looks like there are only baseline changes.
The key change is just a suffix hack. https://github.com/HerringtonDarkholme/vue-ts-loader/commit/d581d4635776429ccf8090c11a1163710ad0a398
And all *.vue files are served to tsc by getScriptSnapshot call rather than readFile on disk. So when a vue file is feed to tsc, it has already been processed by vue-loader.
This is the easiest and fastest way I can come up.
ts-loader needs much maintenance. most test baselines are outdated
I see - would it not be better to have vue-loader generate a different extension for output files when the language="typescript"?
Oh - I think I see. Loaders don't have control over "generating" files. That file exists on its own and no new distinct files are created (even virtually). Is that correct?
Exactly.
I think a good approach is to support non-ts file by loading extension in tsc. And that should be done by vue-ts-loader so that vue-loader has a uniform interface.
So ts-loader should just accept arbitrary file extensions? I think that'd be the right call.
Maybe @mhegazy and @jbrantly can weigh in here on any risks of (or previous issues with) that. Also CCing @TheLarkInn.
Closing, but here's a guide if anyone is trying to get latest vue-loader working with TS2: http://herringtondarkholme.github.io/2016/10/03/vue2-ts2/
add ts-loader with options: AppendTsSuffixTo works. @DanielRosenwasser
@doun How did you do that? Please tell me the details.
@doun It's my fault. I gone well when I remove { modules: false } options in babel.
Here is my webpack2 config.
module: {
rules: [
{
test: /\.js/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// presets: ['es2015', { modules: false }] <- fail
presets: ['es2015']
}
},
{
test: /\.ts$/,
exclude: /node_modules|vue\/src/,
use: [
{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
},
]
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
esModule: true,
}
},
]
}
Has anyone gotten vue2 + typescript2 working with hot reloading using .vue component files?
Yeps, it works nicely. I think the trick it that webpack uses websockets, and there are a few scripts out there that mix this in a not always functional way.
Has anyone gotten vue2 + typescript2 working with hot reloading using .vue component files?
@druppy Yes, I just got it working when I was converting a project over from JavaScript to TypeScript.
See my comment on how I fixed this Error: Could not find file error with ts-loader and appendTsSuffixTo option.
Still won't work for me. Using ts-loader v2.0.3.
references.d.ts:
declare module "*.vue" {
import Vue from 'vue'
export default typeof Vue
}
tsconfig.json:
{
"compilerOptions": {
"lib": [
"dom",
"es5",
"es2015",
"es2015.promise"
],
"module": "es2015",
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules"
]
}
webpack.conf.js:
...
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
esModule: true
}
},
...
Getting this output:
ERROR in ./~/ts-loader!./~/vue-loader/lib/selector.js?type=script&index=0!./src/app.vue
Module build failed: Error: Could not find file: '/home/andrew/Documents/projects/mine-vue/src/app.vue'.
at getValidSourceFile (/home/andrew/Documents/projects/mine-vue/node_modules/typescript/lib/typescript.js:85887:23)
at Object.getEmitOutput (/home/andrew/Documents/projects/mine-vue/node_modules/typescript/lib/typescript.js:86252:30)
at getEmit (/home/andrew/Documents/projects/mine-vue/node_modules/ts-loader/dist/index.js:99:43)
at Object.loader (/home/andrew/Documents/projects/mine-vue/node_modules/ts-loader/dist/index.js:27:11)
@ ./src/app.vue 7:2-94
@ ./src/main.ts
But if i just replace ts-loader with vue-ts-loader and change script attr to lang="vue-ts" in .vue it works fine:
{
test: /\.tsx?$/,
loader: 'vue-ts-loader'
},
Any ideas?
Hey all, here's a sample repo of TypeScript working with .vue files. It's still a bit of a work in progress, but it'll get the job done for you. https://github.com/DanielRosenwasser/typescript-vue-todomvc
It currently uses some augmented .d.ts files that I've been working on, and right now type checking requires that you write
export default Vue.extend({
// ... component options here ...
});
instead of just
export default {
// ... component options here ...
};
You'll also always need an export default from a .vue file so that TypeScript knows that it's a module.
If you use it, try it out with the Vetur VS Code plugin, which can actually give you some of the same experience TypeScript does in .ts files.
vue-loader specific things:
<script lang="ts"> for your script tagsappendTsSuffixTo optionTo import from .vue files, you'll need a declare module "*.vue"-type thing. Specifically this:
declare module '*.vue' {
import Vue from 'vue';
declare const component: typeof Vue;
export default component;
}
which I realize could probably have just been written as
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
@ARomancev maybe your code doesn't work because you're default-exporting the type of Vue, not Vue itself.
@DanielRosenwasser yes, that was the case. Thanks!
Any idea how to use babel loader in conjunction with ts-loader, because this wont work:
{ // ts
test: /\.tsx?$/,
use: [{
loader: 'babel-loader',
}, {
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}],
exclude: /node_modules/,
},
...
{ // vue
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: ExtractTextPlugin.extract(cssExtract(false))
},
options: {
esModule: true
}
}
}
@StevenTheEVILZ why would you need babel if you have TS?
@DanielRosenwasser I've noticed your example repo is using custom vue / vue-router dependencies, does it still require them? if so do you know when they'll be able to work with the official vue/vue-router packages?
@blocka because babel allow you to use es6 api features (non-syntax features) such as iterators, generators, async functions, promises, etc. It automatically polyfills it in for you. That's why lots of people use babel with typescript.
@StevenTheEVILZ babel doesn't automatically pollyfill any run-time behavior for you.
Something about babel-loader polyfills because I can use iterator. But now I realize that the above actually works, and it's not babel causing the problem, it's typescript. Sorry about that.
Does this compile the ts in components twice?
{
test: /\.vue$/,
loader: 'vue-loader', // doesn't want to be use for whatever reason
options: {
loaders: {
scss: cssExtract(false),
ts: [{
loader: 'babel-loader',
}, {
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}]
},
options: {
esModule: true
}
}
},
{ // ts
test: /\.tsx?$/,
use: [{
loader: 'babel-loader',
}, {
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}],
exclude: /node_modules/, // not sure if needed
},
I'm with @mythz in wondering if there is a way to get this working on the vue master branch. @DmacMcgreg asks a good question, and I'm wondering if there is an answer to it using the existing "production APIs" . @DanielRosenwasser 's todoMCV is cool because it's a working example. I just wish Vue truly had first class support for TypeScript in it's best features, like https://vuejs.org/v2/guide/single-file-components.html .
Most helpful comment
Hey all, here's a sample repo of TypeScript working with
.vuefiles. It's still a bit of a work in progress, but it'll get the job done for you. https://github.com/DanielRosenwasser/typescript-vue-todomvcIt currently uses some augmented
.d.tsfiles that I've been working on, and right now type checking requires that you writeinstead of just
You'll also always need an
export defaultfrom a.vuefile so that TypeScript knows that it's a module.If you use it, try it out with the Vetur VS Code plugin, which can actually give you some of the same experience TypeScript does in
.tsfiles.vue-loader specific things:
<script lang="ts">for your script tagsappendTsSuffixTooptionTo import from
.vuefiles, you'll need a declare module "*.vue"-type thing. Specifically this:which I realize could probably have just been written as
@ARomancev maybe your code doesn't work because you're default-exporting the type of Vue, not Vue itself.