web-dev-qa-db-fra.com

Comment puis-je compiler manuellement un composant svelte jusqu'à la finale JavaScript et CSS que SAPPER / Svelte produit?

Notre société produit un cadre d'automatisation écrit à Svelte/Sapper. Une caractéristique est que les développeurs peuvent créer des widgets d'interface utilisateur personnalisés, en utilisant actuellement un fichier JS/HTML/CSS et notre API côté client. Ces widgets sont stockés dans la base de données et non sur le système de fichiers.

Je pense que ce serait un grand avantage de leur permettre de créer des widgets comme composants sveltes car il contient toutes les balises, JS et CSS à un endroit et leur donneraient tous les avantages de la réactivité de Svelte.

J'ai obtenu jusqu'à la création d'un point de terminaison qui compilait les composants à l'aide de l'API de Svelte's Server, mais qui semble générer un module prêt pour Rollup-plugin-svelte/Saper/Babel pour terminer le travail de production de quelque chose que le navigateur peut utiliser.

Comment puis-je compiler manuellement un composant svelte jusqu'à la finale JavaScript et CSS que SAPPER/Svelte produit.

15
mr.freeze

Grâce à la publication détaillée de @rixo, j'ai pu obtenir ce travail. J'ai essentiellement créé un rollup.widget.js comme ceci:

import json from '@rollup/plugin-json';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import svelte from 'rollup-plugin-svelte';
import path from "path";
import fs from "fs";

let basePath = path.join(__dirname,'../widgets');
let srcFiles = fs.readdirSync(basePath).filter(f=>path.extname(f) === '.svelte').map(m=> path.join(basePath,m ));

export default {
    input: srcFiles,
    output: {
        format: 'es',
        dir: basePath,
        sourcemap: true,
    },
    plugins: [
        json(),
        svelte({
            emitCss: false,
            compilerOptions: {
                dev: false,
            },
        }),
        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        commonjs()
    ]
}

Générez ensuite les composants svelte de la base de données et compiler:

const loadConfigFile = require('rollup/dist/loadConfigFile');
        
function compile(widgets){

    return new Promise(function(resolve, reject){
        let basePath = path.join(__dirname,'../widgets');
        
        if (!fs.existsSync(basePath)){
            fs.mkdirSync(basePath);
        }

        for (let w of widgets){
            if (w.config.source){
                let srcFile = path.join(basePath,w.name + '.svelte');
                fs.writeFileSync(srcFile,w.config.source);
                console.log('writing widget source file:', srcFile)
            }
        }

        //ripped off directly from the rollup docs
        loadConfigFile(path.resolve(__dirname, 'rollup.widgets.js'), { format: 'es' }).then(
            async ({ options, warnings }) => {
                console.log(`widget warning count: ${warnings.count}`);
                warnings.flush();

                for (const optionsObj of options) {
                    const bundle = await rollup(optionsObj);
                    await Promise.all(optionsObj.output.map(bundle.write));
                }

                resolve({success: true});
            }
        ).catch(function(x){
            reject(x);
        })    
    })    
}

Puis consommez le widget dynamique comme @rixo proposé:

<script>
    import {onMount, onDestroy, tick} from 'svelte';
    import Widget from "../containers/Widget.svelte";

    export let title = '';
    export let name = '';
    export let config = {};

    let component;
    let target;

    $: if (name){
        loadComponent().then(f=>{}).catch(x=> console.warn(x.message));
    }

    onMount(async function () {
        console.log('svelte widget mounted');
    })

    onDestroy(cleanup);

    async function cleanup(){
        if (component){
            console.log('cleaning up svelte widget');
            component.$destroy();
            component = null;
            await tick();
        }
    }

    async function loadComponent(){
        await cleanup();
        let url = `/widgets/${name}.js?${parseInt(Math.random() * 1000000)}`
        let comp = await import(url);
        component = new comp.default({
            target: target,
            props: config.props || {}
        })
        console.log('loading svelte widget component:', url);
    }

</script>
<Widget name={name} title={title} {...config}>
    <div bind:this={target} class="svelte-widget-wrapper"></div>
</Widget>

Quelques notes/observations:

  1. J'avais beaucoup mieux de chance à l'aide de Rollup/dist/loadconfigfIMFILE que d'essayer d'utiliser Rollup.Rollup directement.
  2. J'ai descendu un trou de lapin d'essayer de créer des globaux de client et de serveur pour tous les modules svelte et les marquer comme externe dans le widget Rollup afin que tout ait utilisé les mêmes internes sveltaires. Cela a fini par être en désordre et a donné accès aux widgets à plus que je ne voulais.
  3. Si vous essayez d'intégrer votre widget compilé de manière dynamique dans votre application principale avec <Svvelte: composant, il fonctionnera en quelque sorte le travail, mais vous donnera la redoutée d'une erreur indéfinie si vous essayez de faire référence à un widget dynamique d'un autre. Après cela, la réalité se décompose et l'application est dans un état étrange.
  4. @rixo a toujours raison. J'ai été averti à propos de chacune de ces choses à l'avance et le résultat était exactement comme prévu.
0
mr.freeze