block by Rich-Harris 51935f475c3954ddaf45ca77b8143a4a

51935f475c3954ddaf45

Full Screen
npm install
npm run build
open index.html

index.html

<!doctype html>
<html>
<head>
	<title>this will change!</title>
</head>
<body>
	<main></main>
	<script src='bundle.js'></script>
</body>
</html>

App.html

<h1>change the title</h1>
<input bind:value='title'>

<Title title='{{title}}'/>

<script>
	import Title from './Title.html';

	export default {
		data () {
			return {
				title: 'dynamic title woo!!!'
			};
		},

		components: {
			Title
		}
	};
</script>

Title.html

<script>
	export default {
		onrender () {
			this.originalTitle = document.title;
			this.observe( 'title', title => document.title = title );
		},

		onteardown () {
			document.title = this.originalTitle;
		}
	};
</script>

app.js

import App from './App.html';

new App({
	target: document.querySelector( 'main' )
});

bundle.js

(function () {
'use strict';

var template$1 = (function () {
	return {
		onrender () {
			this.originalTitle = document.title;
			this.observe( 'title', title => document.title = title );
		},

		onteardown () {
			document.title = this.originalTitle;
		}
	};
}());

function renderMainFragment$1 ( root, component ) {
	

	return {
		mount: function ( target, anchor ) {
			
		},
		
		update: function ( changed, root ) {
			
		},
		
		teardown: function ( detach ) {
			
		}
	};
}

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

	var component = this;
	var state = options.data || {};

	var observers = {
		immediate: Object.create( null ),
		deferred: Object.create( null )
	};

	var callbacks = Object.create( null );

	function dispatchObservers ( group, newState, oldState ) {
		for ( var key in group ) {
			if ( !( key in newState ) ) continue;

			var newValue = newState[ key ];
			var oldValue = oldState[ key ];

			if ( newValue === oldValue && typeof newValue !== 'object' ) continue;

			var callbacks = group[ key ];
			if ( !callbacks ) continue;

			for ( var i = 0; i < callbacks.length; i += 1 ) {
				var callback = callbacks[i];
				if ( callback.__calling ) continue;

				callback.__calling = true;
				callback.call( component, newValue, oldValue );
				callback.__calling = false;
			}
		}
	}

	this.fire = function fire ( eventName, data ) {
		var handlers = eventName in callbacks && callbacks[ eventName ].slice();
		if ( !handlers ) return;

		for ( var i = 0; i < handlers.length; i += 1 ) {
			handlers[i].call( this, data );
		}
	};

	this.get = function get ( key ) {
		return key ? state[ key ] : state;
	};

	this.set = function set ( newState ) {
		var oldState = state;
		state = Object.assign( {}, oldState, newState );
		
		dispatchObservers( observers.immediate, newState, oldState );
		if ( mainFragment ) mainFragment.update( newState, state );
		dispatchObservers( observers.deferred, newState, oldState );
	};

	this._mount = function mount ( target, anchor ) {
		mainFragment.mount( target, anchor );
	};

	this.observe = function ( key, callback, options ) {
		var group = ( options && options.defer ) ? observers.deferred : observers.immediate;

		( group[ key ] || ( group[ key ] = [] ) ).push( callback );

		if ( !options || options.init !== false ) {
			callback.__calling = true;
			callback.call( component, state[ key ] );
			callback.__calling = false;
		}

		return {
			cancel: function () {
				var index = group[ key ].indexOf( callback );
				if ( ~index ) group[ key ].splice( index, 1 );
			}
		};
	};

	this.on = function on ( eventName, handler ) {
		var handlers = callbacks[ eventName ] || ( callbacks[ eventName ] = [] );
		handlers.push( handler );

		return {
			cancel: function () {
				var index = handlers.indexOf( handler );
				if ( ~index ) handlers.splice( index, 1 );
			}
		};
	};

	this.teardown = function teardown ( detach ) {
		this.fire( 'teardown' );
template$1.onteardown.call( this );

		mainFragment.teardown( detach !== false );
		mainFragment = null;

		state = {};
	};

	this.root = options.root;
	this.yield = options.yield;

	var mainFragment = renderMainFragment$1( state, this );
	if ( options.target ) this._mount( options.target );
	
	if ( options.root ) {
		options.root.__renderHooks.push({ fn: template$1.onrender, context: this });
	} else {
		template$1.onrender.call( this );
	}
}

var template = (function () {
	return {
		data () {
			return {
				title: 'dynamic title woo!!!'
			};
		},

		components: {
			Title
		}
	};
}());

function renderMainFragment ( root, component ) {
	var h1 = document.createElement( 'h1' );
	
	h1.appendChild( document.createTextNode( "change the title" ) );
	var text1 = document.createTextNode( "\n" );
	
	var input = document.createElement( 'input' );
	
	var input_updating = false;
	
	function inputChangeHandler () {
		input_updating = true;
		component.set({ title: input.value });
		input_updating = false;
	}
	
	input.addEventListener( 'input', inputChangeHandler, false );
	input.value = root.title;
	
	var text2 = document.createTextNode( "\n\n" );
	
	var title_initialData = {
		title: root.title
	};
	var title = new template.components.Title({
		target: null,
		root: component.root || component,
		data: title_initialData
	});

	return {
		mount: function ( target, anchor ) {
			target.insertBefore( h1, anchor );
			target.insertBefore( text1, anchor );
			target.insertBefore( input, anchor );
			target.insertBefore( text2, anchor );
			title._mount( target, anchor );
		},
		
		update: function ( changed, root ) {
			if ( !input_updating ) input.value = root.title;
			
			var title_changes = {};
			
			if ( 'title' in changed ) title_changes.title = root.title;
			
			if ( Object.keys( title_changes ).length ) title.set( title_changes );
		},
		
		teardown: function ( detach ) {
			input.removeEventListener( 'input', inputChangeHandler, false );
			title.teardown( detach );
			
			if ( detach ) {
				h1.parentNode.removeChild( h1 );
				text1.parentNode.removeChild( text1 );
				input.parentNode.removeChild( input );
				text2.parentNode.removeChild( text2 );
			}
		}
	};
}

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

	var component = this;
	var state = Object.assign( template.data(), options.data );

	var observers = {
		immediate: Object.create( null ),
		deferred: Object.create( null )
	};

	var callbacks = Object.create( null );

	function dispatchObservers ( group, newState, oldState ) {
		for ( var key in group ) {
			if ( !( key in newState ) ) continue;

			var newValue = newState[ key ];
			var oldValue = oldState[ key ];

			if ( newValue === oldValue && typeof newValue !== 'object' ) continue;

			var callbacks = group[ key ];
			if ( !callbacks ) continue;

			for ( var i = 0; i < callbacks.length; i += 1 ) {
				var callback = callbacks[i];
				if ( callback.__calling ) continue;

				callback.__calling = true;
				callback.call( component, newValue, oldValue );
				callback.__calling = false;
			}
		}
	}

	this.fire = function fire ( eventName, data ) {
		var handlers = eventName in callbacks && callbacks[ eventName ].slice();
		if ( !handlers ) return;

		for ( var i = 0; i < handlers.length; i += 1 ) {
			handlers[i].call( this, data );
		}
	};

	this.get = function get ( key ) {
		return key ? state[ key ] : state;
	};

	this.set = function set ( newState ) {
		var oldState = state;
		state = Object.assign( {}, oldState, newState );
		
		dispatchObservers( observers.immediate, newState, oldState );
		if ( mainFragment ) mainFragment.update( newState, state );
		dispatchObservers( observers.deferred, newState, oldState );
		
		while ( this.__renderHooks.length ) {
			var hook = this.__renderHooks.pop();
			hook.fn.call( hook.context );
		}
	};

	this._mount = function mount ( target, anchor ) {
		mainFragment.mount( target, anchor );
	};

	this.observe = function ( key, callback, options ) {
		var group = ( options && options.defer ) ? observers.deferred : observers.immediate;

		( group[ key ] || ( group[ key ] = [] ) ).push( callback );

		if ( !options || options.init !== false ) {
			callback.__calling = true;
			callback.call( component, state[ key ] );
			callback.__calling = false;
		}

		return {
			cancel: function () {
				var index = group[ key ].indexOf( callback );
				if ( ~index ) group[ key ].splice( index, 1 );
			}
		};
	};

	this.on = function on ( eventName, handler ) {
		var handlers = callbacks[ eventName ] || ( callbacks[ eventName ] = [] );
		handlers.push( handler );

		return {
			cancel: function () {
				var index = handlers.indexOf( handler );
				if ( ~index ) handlers.splice( index, 1 );
			}
		};
	};

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

		mainFragment.teardown( detach !== false );
		mainFragment = null;

		state = {};
	};

	this.root = options.root;
	this.yield = options.yield;

	this.__renderHooks = [];
	
	var mainFragment = renderMainFragment( state, this );
	if ( options.target ) this._mount( options.target );
	
	while ( this.__renderHooks.length ) {
		var hook = this.__renderHooks.pop();
		hook.fn.call( hook.context );
	}
}

new App({
	target: document.querySelector( 'main' )
});

}());

package.json

{
  "devDependencies": {
    "rollup": "^0.37.0",
    "rollup-plugin-svelte": "^1.3.0"
  },
  "scripts": {
    "build": "rollup -c"
  }
}

rollup.config.js

import svelte from 'rollup-plugin-svelte';

export default {
	entry: 'app.js',
	dest: 'bundle.js',
	format: 'iife',
	plugins: [ svelte() ]
};