Skip to content

How to do async components in browserify #620

Closed
@taoeffect

Description

@taoeffect

Currently this page claims that this is "not possible":

If you're a Browserify user that would like to use async components, it's unfortunately not possible and probably never will be, as its creator has made it clear that async loading "is not something that Browserify will ever support." If this is a feature that's important to you, we recommend using Webpack instead.

It is in fact possible to do code splitting just fine with browserify. We're doing it in our project.

For example, when using grunt-browserify, as part of its config you can specify which components you want to create that are standalone, as I do here using a custom browserifyCfg function to generate the config:

    browserify: browserifyCfg({
      straight: [{ 'dist/simple/app.js': ['frontend/simple/main.js'] }],
      lazy: [{ 'dist/simple/js/UserGroupView.js': ['frontend/simple/views/UserGroupView.vue'] }]
    }),

Thus UserGroupView is created as a separate file from the rest of the bundle. Here's the (simplified) code for browserifyCfg:

function browserifyCfg ({straight, lazy}, cfg = {}) {
  var globalize = x => // views/UserGroupView.vue -> UserGroupView
    S(path.parse(x).name).dasherize().capitalize().camelize().s
  var keyify = x => // views/UserGroupView.vue -> userGroupView
    S(path.parse(x).name).dasherize().chompLeft('-').camelize().s
  var p = (s, ...v) => _.flatten(_.zip(s, v)).join('').replace('/', path.sep)

  function gencfg (out, paths, isLazy) {
    var c = {
      options: {
        transform: ['vueify', 'babelify']
      },
      files: _.fromPairs([[out, paths]])
    }
    if (isLazy) {
      c.options.browserifyOptions.standalone = globalize(out) // <-- this creates a standalone file
      c.options.exclude = ['vue', 'vue-hot-reload-api']
    }
    return c
  }
  for (let map of straight) {
    for (let out in map) {
      cfg[keyify(out)] = gencfg(out, map[out], false)
    }
  }
  for (let map of lazy) {
    for (let out in map) {
      cfg[keyify(out)] = gencfg(out, map[out], true)
    }
  }
  return cfg
}

And then you lazily load the component using a library like VueScript2, e.g.:

import VS2 from 'vue-script2'
Vue.use(VS2)

function lazyLoadVue (component, base = '/js') {
  return function (resolve, reject) {
    VS2.load(`${base}/${component}.js`)
    .then(() => resolve(window[component]))
    .catch((err) => reject(err))
  }
}

// lazy load the component
lazyLoadVue('UserGroupView')

Alternatively, there's also Yahoo's extractify browserify transform, which is a:

Browserify plugin to extract code to be lazy loaded into separate bundles

Not sure if that's relevant/useful tho.

Activity

taoeffect

taoeffect commented on Nov 30, 2016

@taoeffect
Author

I can submit a PR to address this, but am not sure what form it should take. It could just be a link to this issue as an example of how to do it. Or w/e.

chrisvfritz

chrisvfritz commented on Nov 30, 2016

@chrisvfritz
Contributor

Thanks for sharing this workaround @taoeffect! 🎉 I just updated that note with a link to this thread, which I'll close now, but still welcome people to share any techniques they've found helpful to get past this limitation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @taoeffect@chrisvfritz

        Issue actions

          How to do async components in browserify · Issue #620 · vuejs/v2.vuejs.org