itsfrank / vue-typescript

Typescript decorators to make vue feel more typescripty
MIT License
357 stars 25 forks source link

including javascript libraries like vue-strap #9

Closed davidmoshal closed 8 years ago

davidmoshal commented 8 years ago

Hi, wondering how best to import a library like vue-strap?

Thanks

davidmoshal commented 8 years ago

I tried import 'vue-strap' which makes webpack happy, but the browser fails with:

[Vue warn]: Unknown custom element: <radio-group> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
[Vue warn]: Unknown custom element: <radio-btn> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
[vue-devtools] Ready. Detected Vue v1.0.26
davidmoshal commented 8 years ago

2 related questions:

1) is it possible to use .js / .vue files from vue-typescript? this feature would help with migrating existing js vue projects to ts.

2) is there a strategy for migrating entire vue component libraries (e.g. vue-strap). looking at the vue-strap codebase it seems possible to convert to ts, but then how would you export that library for use by a vue-typecript project?

davidmoshal commented 8 years ago

Seems like the following works for Radio Buttons:

import * as Vue from 'vue'
import { VueComponent, Prop, Watch } from 'vue-typescript'
import { store } from '../../store'

@VueComponent({
  template: `
        <span v-for="p in pages">
          <input type="radio" name="rb_current_page" :id="p" :value="p" v-model="current_page">
          <label :for="p">{{p}}</label>
        </span>`
})
export class Navbar extends Vue{
  pages = ['Home', 'User', 'Credit']

  get current_page(){
    console.log('getting next_page')
    return store.state.currentPage
  }

  set current_page( val ){
    console.log({val})
    store.dispatch('SET_PAGE', val)
  }
}
itsfrank commented 8 years ago

I've worked with vue-strap shortly in a project recently, ill comment on this in detail after I get off work.

itsfrank commented 8 years ago

Ok so you touched on a bunch of stuff here.

So for vue-strap, none of the components are globally declared, so you need to declare them in the 'components' option. When I used it, I had to do something like this:

import { VueComponent } from 'vue-typescript'
import { theComponent } from 'vue-strap' 

@VueComponent({
    template: '<tc></tc>',
    components: {
        tc: theComponent
    }
})
export class MyComponent {...}

For this to work, i had to write my own type definition file:

declare module 'vue-strap' {
    export var alert:any
    export var carousel:any
    export var slider:any
    export var accordion:any
    export var affix:any
    export var aside:any
    export var checkboxBtn:any
    export var checkboxGroup:any
    export var datepicker:any
    export var dropdown:any
    export var modal:any
    export var option:any
    export var panel:any
    export var popover:any
    export var progressbar:any
    export var radioGroup:any
    export var radioBtn:any
    export var select:any
    export var tab:any
    export var tabset:any
    export var tooltip:any
    export var typeahead:any
    export var navbar:any
    export var spinner:any
}

if you don't want to bother with this, i'm pretty sure this will work as well:

import { VueComponent } from 'vue-typescript'
var someComponent = require('vue-strap').someComponent

@VueComponent({
    template: '<some-component ></some-component >',
    components: {
        someComponent 
    }
})
export class MyComponent {...}

So I currently don't have time to properly try this, I'm juggling with two deliverables and trying to get vue-typescript 1.0 ready, so I'm just going from memory, however if you get it to work can you please post the definitive solution?

itsfrank commented 8 years ago

As for migrating component libraries to typescript, there is no need, vue-typescript is a quality-of-life library, it doesn't impose anything on you. Just like i showed you in the above comment, any pre-made component can be imported in the same way regardless of the language it was written in.

For using .js and .vue files, as long as you have the proper loader in webpack, there is no reason why you wouldn't be able to import them once again in the same way as above.

For a .vue file that uses the export default syntax, it would work like this:

import { VueComponent } from 'vue-typescript'
import * as dotVueComponent from './component.vue'

@VueComponent({
    template: '<dot-vue-component></dot-vue-component>',
    components: {
        dotVueComponent
    }
})
export class MyComponent {...}

I personally looked into hacking vue-loader and generating vue-typescript files from .vue components, but i ended up dropping it. Might give it another go in the future.

itsfrank commented 8 years ago

For migrating, after i showed vue-typescript to my project manager, he asked me to migrate our entire app based on .vue files to vue-typescript. That's when io started looking into the converter i talked about above, it would have taken toot long so i didi it manually, which was suprisingly easy.

My strategy was like so:

it took me about half a day to migrate an app that had roughly 30 components

itsfrank commented 8 years ago

hope this left you less confused than when you started, let me know if you find any oddities or have any concerns

davidmoshal commented 8 years ago

thanks, fabulous advice!

I might take a look at building that converter for you, once I get a bit more experience with vue and vue-typescript.

Thanks again for an awesome project, definitely a Quality-of-life framework!

Note: in my example above, I'm actually 'binding' an input to Vuex, if that wasn't clear!

i.e:

<input v-model="foo"></input>

get foo(){
  return vuex_store.state.foo
}

set foo(val){
  vuex_store.dispatch('SET_FOO', val)
}

couldn't be more simple than that!

itsfrank commented 8 years ago

Ill close this for now as there is no issue relevant to the source here, however open up new ones if you have any other concerns or questions

davidmoshal commented 8 years ago

Your second version worked perfectly for me. I didn't try the declaration file, but I should probably to that at some point. Note: again using vuex to store the state.

import * as Vue from 'vue'
import { VueComponent } from 'vue-typescript'
const {radioBtn, radioGroup} = require('vue-strap')
import {store} from '../../store'

@VueComponent({
  template  : ` <table style="width: 100%">
    <tr>
      <td style="width: 200px; text-align: right">
        <radio-group :value.sync="current_page">
          <radio-btn value="HOME">Home</radio-btn>
          <radio-btn value="USER">Users</radio-btn>
          <radio-btn value="CREDIT">Credit</radio-btn>
        </radio-group>
      </td>
    </tr>
  </table>`,
  components: {radioBtn, radioGroup}
})
export class Navbar extends Vue{

  get current_page(){
    //console.log('getting next_page')
    return store.state.currentPage
  }

  set current_page( val ){
    //console.log({val})
    store.dispatch('SET_PAGE', val)
  }

}
itsfrank commented 8 years ago

Good news! thanks for the followup!