Harshal Patil
Harshal Patil

Reputation: 21030

Can I move JS code out of Svelte component file to other file js file?

I am currently exploring Bucklescript/ReasonML with Svelte 3 for my next project. Typical Svelte component is a .svelte file:

<script>
  let name = 'world';
</script>

<h1>Hello world!</h1>

Instead, can I have script tag with src or equivalent to keep JS code in a separate file?

<script src='./some-file.js'></script>

By moving the js code to a separate file, the target of the Bucklescript compiler (which is a JS file) could be used for the component.

Vue.js already supports this with their SFC .vue file.

On a side note: I could use Vue.js for this but the presence Virtual DOM is problematic for legacy codebase. And, Svelte is diminishing at runtime and thus very much desirable. Also, the use this in Vue makes things awkward in Ocaml/Reason.

Upvotes: 16

Views: 4086

Answers (2)

Rich Harris
Rich Harris

Reputation: 29615

This is possible with the svelte.preprocess API, which you'd most commonly reach via the preprocess option in rollup-plugin-svelte or svelte-loader. Something like this should work (though I haven't tested it):

const path = require( 'path' )
const fs = require( 'fs' )
...

plugins: [
  svelte({
    // ...
    preprocess: {
      script: ({ content, attributes, filename }) => {
        if ( 'string' === typeof attributes.src ) {
          const file = path.resolve(path.dirname(filename), attributes.src);
          const code = fs.readFileSync(file, 'utf-8');
          return {code, dependencies: [file]};
        }
      }
    }
  })
]

Upvotes: 13

Morphyish
Morphyish

Reputation: 4072

As far as I know, this isn't possible right now.

What you could do is export everything you need from the js file, and then import them in the component: https://svelte.dev/repl/1d630ff27a0c48d38e4762cf6b0c2da5?version=3.7.1

<script>
 import { name } from './mycode.js'
</script>

<h1>Hello {name}!</h1>
export let name = 'World';

However that would only be a partial solution as any mutation of data occurring within the file would not trigger a re-render of the DOM, as Svelte would not compile the .js file and would not be able to add its own code invalidating the values: https://svelte.dev/repl/c4b41b769ed747acb01a02a9af33e545?version=3.7.1

<script>
 import { name, handleClick } from './mycode.js'
</script>

<h1 on:click={handleClick}>Hello {name}!</h1>
export let name = 'World';
export const handleClick = () => {
    name = 'Everyone';
}

But that doesn't mean you can't be tricky if you are willing to go the extra mile to achieve this: https://svelte.dev/repl/8e259df629614ac99cb14cfae2f30658?version=3.7.1

<script>
 import { name, handleClick } from './mycode.js'

 const onClick = () => {
     handleClick();
     name = name;
 }
</script>

<h1 on:click={onClick}>Hello {name}!</h1>
export let name = 'World';
export const handleClick = () => {
    name = 'Everyone';
}

The extra line name = name forcing the DOM update.

Upvotes: 2

Related Questions