Bud Vue - loader not applying to files outside of the @src

When I include vue files in my admin entry, from the sage resources path (@src) - and everything works fine:

        admin: [
          "@src/vue/index.js",
        ]

The contents of this index:

import { createApp } from 'vue'
// import the root component App from a single-file component.
import App from './App.vue'

const app = createApp(App)
app.mount('#app')

When I try to include vue files from a different folder, things go sideways:

        admin: [
          "./components/assets/vue/index.js",
        ]
├─ ✘ error
│ ModuleParseError: Module parse failed: Unexpected token (1:0)
│ You may need an appropriate loader to handle this file type, currently no loaders are configured to process this
file. See https://webpack.js.org/concepts#loaders
│ > <template>
│ |     <h1>Gday!</h1>
│ | </template>

I encountered this with sass files, so I added this in for sass/js outside the @src path:
(Hattip to @kellymears for enlightening me about this on the github issues:)

  app.hooks.action(`config.after`, async (app) => {
    app.build.rules.js.setInclude([
      bud => bud.path('@src'),
      app => app.path('./components'),
    ])

    app.build.rules.sass.setInclude([
      app => app.path('@src'),
      app => app.path('./components'),
    ])
  })

I assumed that adding in another block like so would work, but it does not:

    app.build.rules.vue.setInclude([
      app => app.path('@src'),
      app => app.path('./components'),
    ])

Can anyone see what I’m doing wrong here?

After looking at the documentation, i tried the following: ‘To be maximally accepting of what you want to transpile, you can use the following snippet’:

  app.hooks.action(`config.after`, async app => {
    Object.values(app.build.rules).map(rule =>
      rule.setInclude([
        app => app.path('@src'),
        app => app.path('./components'),
      ]),
    )
  })

But that still didn’t work.

Vue is a special case because it is not compatible with webpack’s oneOf style rules. I don’t remember what their rationale is (if any has been provided).

Rules are parsed in three groups, in the following order:

  • build.module.rules.before - called for every module
  • build.module.rules.oneOf - all rules except vue are applied here
  • build.module.rules.after - called for every module (this is unused by bud internally, but the hook is provided and called in case there is user need).

build.module.rules.oneOf is the preferred group because it doesn’t apply modules unnecessarily. Once it finds a match it exits:

oneOf: an array of Rules from which only the first matching Rule is used when the Rule matches.

@roots/bud-vue has to add vue-loader to the list of rules which are applied to all modules, and it does so by adding it to the rules in build.module.rules.before.

The easiest way to make modifications to the vue rule at the moment is to hook build.module.rules.before:

bud.hooks.on(`build.module.rules.before`, (ruleset) => {
  // make modifications to ruleset array here
  return ruleset
})

I’m not 100% certain but I believe there is one other rule in the array. This rule ensures that browser incompatible code isn’t included in the bundle. I believe that the vue rule should be the first of the two rules, but you can throw in a console log and find out for yourself:

bud.hooks.on(`build.module.rules.before`, (ruleset) => {
  // make modifications to ruleset array here
  console.log(ruleset)
  process.exit()

  return ruleset
})

If it were the first array item, the final code would probably be something like this:

bud.hooks.on(`build.module.rules.before`, (ruleset) => {
  // make modifications to ruleset array here
  ruleset[0].include = [bud.path('./components'), ...ruleset[0].include]
  return ruleset
})

We need to document this and also provide a way to configure it (bud.vue.setInclude or something). But, nobody has asked yet! I’ll try to prioritize that in the near future now that I see the need.

1 Like

if for whatever reason you have problems logging the ruleset in the hook you might want to try out the bud repl cli command:

It can be handy for exploring the shape of the generated config (bud.build.config).

1 Like

This is phenomenal, I really appreciate this response.


An aside: My theme is an extension of Sage, where pages are composed of components rather than traditional page templates. Each Component is a self-contained folder with assets, schema, function, and js for customElements. Needless to say, it has some unique requirements for my bud config and beyond.

The components are also responsible for enqueuing its own assets when included in. a page in production (vs a complete bundle with HMR in development) , so less of a monolithic bundle, and more versioned component js/css files.

It does some fun things with ACF composer, hooking into the View Composers config to load from other directories, as well as a rudimentary CLI for creating components and importing them from a github repo of base components.

It makes for portable components across projects and the ability to scaffold a project pretty quickly from some start components

If you or anyone else would be interested in seeing it, let me know. It has sped up the way I build projects for all of our clients.

3 Likes

I’d like to see it. Thank you

Sounds neat; I’d also be interested in seeing it. I’m wondering if there might be a way to leverage multiple compilers for this, since each is self-contained.

I’ve just started something similar, would love to see your repo, if you’re willing to share. Thanks :slight_smile: