Sapper: Make components/Foo.html a universally-available <Foo> component

Created on 26 Mar 2018  路  4Comments  路  Source: sveltejs/sapper

This came up in Gitter the other day, and it would be a nice quality-of-life improvement. If every **/*.html file in a components directory was made available without needing to be explicitly imported, we could save ourselves some boilerplate.

It'd require a change to Svelte itself. I initially suggested something like this...

result = svelte.compile(source, {
  injectComponents: glob.sync('src/**/*.html').reduce((map, file) => {
    const name = path.basename(file).replace(/\.html$/, '');
    map[name] = path.relative(fileBeingCompiled, file);
    return map;
  }, {})
});

...though maybe the user should supply a search function instead? (The approach above wouldn't work if the contents of components changed during development, because webpack wouldn't know about it.) So perhaps this:

result = svelte.compile(source, {
  injectComponent: name => {
    const files = glob.sync(`**/${name}.html`, { cwd: 'components' });
    if (files.length > 1) throw new Error(`Multiple components called ${name}.html`);
    return files[0];
  }
});

Reglobbing each time isn't ideal, obviously, but in practice I don't think it'd be an issue (and you could supply a more sophisticated search function if you wanted).

In the context of a Sapper webpack config, it would mean adding something like this to both client and server configs:

const config = require('sapper/webpack/config.js');

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.html$/,
        exclude: /node_modules/,
        use: {
          loader: 'svelte-loader',
          options: {
            hydratable: true,
            cascade: false,
            store: true,
            hotReload: true,
+            injectComponent: config.inject()
          }
        }
      }
    ]
  },
  // ...
};

Alternatively, it could belong in preprocess, which would make it unnecessary to change anything in Svelte itself (though the implementation would be somewhat hackier, since it would presumably be based on naive string matching).

Of course, there is a good reason not to do any of this, which is that explicit > implicit, even when it's less convenient.

Most helpful comment

I think there's still something to be set for this suggestion. It's slightly wonkier syntax, but it is more explicit, and doesn't require any conventions or special handling in Sapper.

All 4 comments

I think there's still something to be set for this suggestion. It's slightly wonkier syntax, but it is more explicit, and doesn't require any conventions or special handling in Sapper.

Another approach would be that sapper dev --auto-import actually changes your source code and writes the boilerplate for you. (only right after saving, if the import is missing and if the component can be found in a specific folder)

I would rather it stay explicit. There is enough magic going on in Javascript already.

The src/node_modules idea takes care of it being inconvenient to import from far away paths. Svelte 3 also naturally reduces some boilerplate when importing components, while also moving toward more things being explicit. Closing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

benmccann picture benmccann  路  3Comments

BMorearty picture BMorearty  路  3Comments

milosdjakovic picture milosdjakovic  路  3Comments

freedmand picture freedmand  路  4Comments

Snugug picture Snugug  路  4Comments