Skip to content

Conversation

@Rich-Harris
Copy link
Member

This PR adds support for non-standalone components, per #9, via the standalone: false (subject to bikeshedding) option. With this setting, apps with multiple components can reuse code efficiently.

A <h1>Hello {{name}}!</h1> template compiles like so:

import { get, fire, observe, on, dispatchObservers, createElement, detachNode, insertNode, appendNode, createText } from 'svelte/shared.js'

function renderMainFragment ( root, component ) {
    var h1 = createElement( 'h1' );

    appendNode( createText( "Hello " ), h1 );
    var text1 = createText( root.name );
    appendNode( text1, h1 );
    appendNode( createText( "!" ), h1 );

    return {
        mount: function ( target, anchor ) {
            insertNode( h1, target, anchor );
        },

        update: function ( changed, root ) {
            text1.data = root.name;
        },

        teardown: function ( detach ) {
            if ( detach ) {
                detachNode( h1 );
            }
        },
    };
}

function SvelteComponent ( options ) {
    options = options || {};

    this._state = options.data || {};

    this._observers = {
        pre: Object.create( null ),
        post: Object.create( null )
    };

    this._handlers = Object.create( null );

    this._root = options._root;
    this._yield = options._yield;

    this._fragment = renderMainFragment( this._state, this );
    if ( options.target ) this._fragment.mount( options.target, null );
}

SvelteComponent.prototype.get = get;
SvelteComponent.prototype.fire = fire;
SvelteComponent.prototype.observe = observe;
SvelteComponent.prototype.on = on;

SvelteComponent.prototype.set = function set ( newState ) {
    var oldState = this._state;
    this._state = Object.assign( {}, oldState, newState );

    dispatchObservers( this, this._observers.pre, newState, oldState );
    if ( this._fragment ) this._fragment.update( newState, this._state );
    dispatchObservers( this, this._observers.post, newState, oldState );
};

SvelteComponent.prototype.teardown = function teardown ( detach ) {
    this.fire( 'teardown' );

    this._fragment.teardown( detach !== false );
    this._fragment = null;

    this._state = {};
};

export default SvelteComponent;

We could go further, by deduplicating some of the set/teardown/constructor stuff (which can vary from component to component), though the returns are diminishing.

This PR exacerbates an existing problem, which is that we need more complete name deconflicting – at present, we could end up with conflicts between our functions and the user's imports, and with each block variables shadowing helpers. But I think that warrants a separate issue, and shouldn't block this change.

@Conduitry
Copy link
Member

Would it be worthwhile to instead do something like

import * as svelteShared from 'svelte/shared.js'

so that there's only one name there might be a collision with?

@Rich-Harris
Copy link
Member Author

Could do. Though we still need a mechanism for reliable deconflicting, and I suppose once you've got that it doesn't really matter whether you're deconflicting one thing or several. Also I'm not sure what the impact would be on bundles – Rollup can resolve namespaced imports back to the function declaration (meaning unused functions get treeshaken away), I'm not 100% sure if Webpack can or not.

@Conduitry
Copy link
Member

That's fair. I was mostly suggesting this as a possible alternative if you thought that proper deconflicting was still a ways off.

And to be honest I was only considering Rollup when I suggested this, I wasn't thinking about Webpack or others at all. 😄 It definitely seems possible that they wouldn't be able to remove the unused code in that case, which would make me rescind my suggestion.

@Rich-Harris Rich-Harris merged commit b23572d into master Dec 20, 2016
@Rich-Harris Rich-Harris deleted the non-standalone branch December 20, 2016 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants