Skip to content

Non-standalone components #215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 20, 2016
Merged

Non-standalone components #215

merged 4 commits into from
Dec 20, 2016

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.

2 participants