diff --git a/.gitignore b/.gitignore
index 7ecf62a..57aee3f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,19 +1,14 @@
.DS_Store
yarn.lock
+yarn-error.log
node_modules
cypress/screenshots
test/app/.sapper
test/app/app/manifest
test/app/export
test/app/build
-runtime.js
-runtime.js.map
-cli.js
-cli.js.map
-middleware.js
-middleware.js.map
-core.js
-core.js.map
-webpack/config.js
-webpack/config.js.map
-yarn-error.log
\ No newline at end of file
+*.js
+*.js.map
+*.ts.js
+*.ts.js.map
+!rollup.config.js
\ No newline at end of file
diff --git a/middleware.js b/middleware.js
new file mode 100644
index 0000000..9e3b243
--- /dev/null
+++ b/middleware.js
@@ -0,0 +1,2 @@
+// TODO write to this file, instead of middleware.ts.js
+module.exports = require('./middleware.ts.js');
\ No newline at end of file
diff --git a/package.json b/package.json
index 358fb4a..2ee260d 100644
--- a/package.json
+++ b/package.json
@@ -4,15 +4,12 @@
"description": "Military-grade apps, engineered by Svelte",
"main": "middleware.js",
"bin": {
- "sapper": "cli.js"
+ "sapper": "./sapper"
},
"files": [
- "cli.js",
- "core.js",
- "middleware.js",
+ "*.js",
+ "*.ts.js",
"runtime",
- "runtime.js",
- "sapper-dev-client.js",
"webpack"
],
"directories": {
@@ -51,7 +48,7 @@
"mocha": "^4.0.1",
"nightmare": "^2.10.0",
"npm-run-all": "^4.1.2",
- "rollup": "^0.53.0",
+ "rollup": "^0.56.5",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-string": "^2.0.2",
diff --git a/rollup.config.js b/rollup.config.js
index 6bad2d6..cea6673 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -10,36 +10,39 @@ const external = [].concat(
'sapper/core.js'
);
-const paths = {
- 'sapper/core.js': './core.js'
-};
-
-const plugins = [
- string({
- include: '**/*.md'
- }),
- json(),
- commonjs(),
- typescript({
- typescript: require('typescript')
- })
-];
-
export default [
- { name: 'cli', banner: true },
- { name: 'core' },
- { name: 'middleware' },
- { name: 'runtime', format: 'es' },
- { name: 'webpack', file: 'webpack/config' }
-].map(obj => ({
- input: `src/${obj.name}/index.ts`,
- output: {
- file: `${obj.file || obj.name}.js`,
- format: obj.format || 'cjs',
- banner: obj.banner && '#!/usr/bin/env node',
- paths,
- sourcemap: true
+ {
+ input: `src/runtime/index.ts`,
+ output: {
+ file: `runtime.js`,
+ format: 'es'
+ },
+ plugins: [
+ typescript({
+ typescript: require('typescript')
+ })
+ ]
},
- external,
- plugins
-}));
+
+ {
+ input: [`src/cli.ts`, `src/core.ts`, `src/middleware.ts`, `src/webpack.ts`],
+ output: {
+ dir: '.',
+ format: 'cjs',
+ sourcemap: true
+ },
+ external,
+ plugins: [
+ string({
+ include: '**/*.md'
+ }),
+ json(),
+ commonjs(),
+ typescript({
+ typescript: require('typescript')
+ })
+ ],
+ experimentalCodeSplitting: true,
+ experimentalDynamicImport: true
+ }
+];
\ No newline at end of file
diff --git a/runtime.js b/runtime.js
new file mode 100644
index 0000000..a3db060
--- /dev/null
+++ b/runtime.js
@@ -0,0 +1,271 @@
+function detach(node) {
+ node.parentNode.removeChild(node);
+}
+function findAnchor(node) {
+ while (node && node.nodeName.toUpperCase() !== 'A')
+ node = node.parentNode; // SVG elements have a lowercase name
+ return node;
+}
+function which(event) {
+ return event.which === null ? event.button : event.which;
+}
+function scroll_state() {
+ return {
+ x: window.scrollX,
+ y: window.scrollY
+ };
+}
+
+var component;
+var target;
+var routes;
+var errors;
+var history = typeof window !== 'undefined' ? window.history : {
+ pushState: function (state, title, href) { },
+ replaceState: function (state, title, href) { },
+ scrollRestoration: ''
+};
+var scroll_history = {};
+var uid = 1;
+var cid;
+if ('scrollRestoration' in history) {
+ history.scrollRestoration = 'manual';
+}
+function select_route(url) {
+ if (url.origin !== window.location.origin)
+ return null;
+ var _loop_1 = function (route) {
+ var match = route.pattern.exec(url.pathname);
+ if (match) {
+ if (route.ignore)
+ return { value: null };
+ var params = route.params(match);
+ var query_1 = {};
+ if (url.search.length > 0) {
+ url.search.slice(1).split('&').forEach(function (searchParam) {
+ var _a = /([^=]+)=(.*)/.exec(searchParam), key = _a[1], value = _a[2];
+ query_1[key] = value || true;
+ });
+ }
+ return { value: { url: url, route: route, data: { params: params, query: query_1 } } };
+ }
+ };
+ for (var _i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
+ var route = routes_1[_i];
+ var state_1 = _loop_1(route);
+ if (typeof state_1 === "object")
+ return state_1.value;
+ }
+}
+var current_token;
+function render(Component, data, scroll, token) {
+ if (current_token !== token)
+ return;
+ if (component) {
+ component.destroy();
+ }
+ else {
+ // first load — remove SSR'd contents
+ var start = document.querySelector('#sapper-head-start');
+ var end = document.querySelector('#sapper-head-end');
+ if (start && end) {
+ while (start.nextSibling !== end)
+ detach(start.nextSibling);
+ detach(start);
+ detach(end);
+ }
+ }
+ component = new Component({
+ target: target,
+ data: data,
+ hydrate: !component
+ });
+ if (scroll) {
+ window.scrollTo(scroll.x, scroll.y);
+ }
+}
+function prepare_route(Component, data) {
+ var redirect = null;
+ var error = null;
+ if (!Component.preload) {
+ return { Component: Component, data: data, redirect: redirect, error: error };
+ }
+ if (!component && window.__SAPPER__ && window.__SAPPER__.preloaded) {
+ return { Component: Component, data: Object.assign(data, window.__SAPPER__.preloaded), redirect: redirect, error: error };
+ }
+ return Promise.resolve(Component.preload.call({
+ redirect: function (statusCode, location) {
+ redirect = { statusCode: statusCode, location: location };
+ },
+ error: function (statusCode, message) {
+ error = { statusCode: statusCode, message: message };
+ }
+ }, data))["catch"](function (err) {
+ error = { statusCode: 500, message: err };
+ }).then(function (preloaded) {
+ if (error) {
+ var route = error.statusCode >= 400 && error.statusCode < 500
+ ? errors['4xx']
+ : errors['5xx'];
+ return route.load().then(function (_a) {
+ var Component = _a["default"];
+ var err = error.message instanceof Error ? error.message : new Error(error.message);
+ Object.assign(data, { status: error.statusCode, error: err });
+ return { Component: Component, data: data, redirect: null };
+ });
+ }
+ Object.assign(data, preloaded);
+ return { Component: Component, data: data, redirect: redirect };
+ });
+}
+function navigate(target, id) {
+ if (id) {
+ // popstate or initial navigation
+ cid = id;
+ }
+ else {
+ // clicked on a link. preserve scroll state
+ scroll_history[cid] = scroll_state();
+ id = cid = ++uid;
+ scroll_history[cid] = { x: 0, y: 0 };
+ }
+ cid = id;
+ var loaded = prefetching && prefetching.href === target.url.href ?
+ prefetching.promise :
+ target.route.load().then(function (mod) { return prepare_route(mod["default"], target.data); });
+ prefetching = null;
+ var token = current_token = {};
+ return loaded.then(function (_a) {
+ var Component = _a.Component, data = _a.data, redirect = _a.redirect;
+ if (redirect) {
+ return goto(redirect.location, { replaceState: true });
+ }
+ render(Component, data, scroll_history[id], token);
+ });
+}
+function handle_click(event) {
+ // Adapted from https://github.com/visionmedia/page.js
+ // MIT license https://github.com/visionmedia/page.js#license
+ if (which(event) !== 1)
+ return;
+ if (event.metaKey || event.ctrlKey || event.shiftKey)
+ return;
+ if (event.defaultPrevented)
+ return;
+ var a = findAnchor(event.target);
+ if (!a)
+ return;
+ // check if link is inside an svg
+ // in this case, both href and target are always inside an object
+ var svg = typeof a.href === 'object' && a.href.constructor.name === 'SVGAnimatedString';
+ var href = String(svg ? a.href.baseVal : a.href);
+ if (href === window.location.href) {
+ event.preventDefault();
+ return;
+ }
+ // Ignore if tag has
+ // 1. 'download' attribute
+ // 2. rel='external' attribute
+ if (a.hasAttribute('download') || a.getAttribute('rel') === 'external')
+ return;
+ // Ignore if has a target
+ if (svg ? a.target.baseVal : a.target)
+ return;
+ var url = new URL(href);
+ // Don't handle hash changes
+ if (url.pathname === window.location.pathname && url.search === window.location.search)
+ return;
+ var target = select_route(url);
+ if (target) {
+ navigate(target, null);
+ event.preventDefault();
+ history.pushState({ id: cid }, '', url.href);
+ }
+}
+function handle_popstate(event) {
+ scroll_history[cid] = scroll_state();
+ if (event.state) {
+ var url = new URL(window.location.href);
+ var target_1 = select_route(url);
+ navigate(target_1, event.state.id);
+ }
+ else {
+ // hashchange
+ cid = ++uid;
+ history.replaceState({ id: cid }, '', window.location.href);
+ }
+}
+var prefetching = null;
+function prefetch(href) {
+ var selected = select_route(new URL(href));
+ if (selected) {
+ prefetching = {
+ href: href,
+ promise: selected.route.load().then(function (mod) { return prepare_route(mod["default"], selected.data); })
+ };
+ }
+}
+function handle_touchstart_mouseover(event) {
+ var a = findAnchor(event.target);
+ if (!a || a.rel !== 'prefetch')
+ return;
+ prefetch(a.href);
+}
+var inited;
+function init(_target, _routes) {
+ target = _target;
+ routes = _routes.filter(function (r) { return !r.error; });
+ errors = {
+ '4xx': _routes.find(function (r) { return r.error === '4xx'; }),
+ '5xx': _routes.find(function (r) { return r.error === '5xx'; })
+ };
+ if (!inited) {
+ window.addEventListener('click', handle_click);
+ window.addEventListener('popstate', handle_popstate);
+ // prefetch
+ window.addEventListener('touchstart', handle_touchstart_mouseover);
+ window.addEventListener('mouseover', handle_touchstart_mouseover);
+ inited = true;
+ }
+ return Promise.resolve().then(function () {
+ var _a = window.location, hash = _a.hash, href = _a.href;
+ var deep_linked = hash && document.getElementById(hash.slice(1));
+ scroll_history[uid] = deep_linked ?
+ { x: 0, y: deep_linked.getBoundingClientRect().top } :
+ scroll_state();
+ history.replaceState({ id: uid }, '', href);
+ var target = select_route(new URL(window.location.href));
+ return navigate(target, uid);
+ });
+}
+function goto(href, opts) {
+ if (opts === void 0) { opts = { replaceState: false }; }
+ var target = select_route(new URL(href, window.location.href));
+ if (target) {
+ navigate(target, null);
+ if (history)
+ history[opts.replaceState ? 'replaceState' : 'pushState']({ id: cid }, '', href);
+ }
+ else {
+ window.location.href = href;
+ }
+}
+function prefetchRoutes(pathnames) {
+ if (!routes)
+ throw new Error("You must call init() first");
+ return routes
+ .filter(function (route) {
+ if (!pathnames)
+ return true;
+ return pathnames.some(function (pathname) {
+ return route.error
+ ? route.error === pathname
+ : route.pattern.test(pathname);
+ });
+ })
+ .reduce(function (promise, route) {
+ return promise.then(route.load);
+ }, Promise.resolve());
+}
+
+export { component, prefetch, init, goto, prefetchRoutes, prefetchRoutes as preloadRoutes };
diff --git a/sapper b/sapper
new file mode 100755
index 0000000..3f0b783
--- /dev/null
+++ b/sapper
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./cli.ts.js');
\ No newline at end of file
diff --git a/src/cli.ts b/src/cli.ts
new file mode 100755
index 0000000..eeb7814
--- /dev/null
+++ b/src/cli.ts
@@ -0,0 +1,77 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import * as child_process from 'child_process';
+import sade from 'sade';
+import * as clorox from 'clorox';
+import prettyMs from 'pretty-ms';
+// import upgrade from './cli/upgrade';
+import * as ports from 'port-authority';
+import * as pkg from '../package.json';
+
+const prog = sade('sapper').version(pkg.version);
+
+prog.command('dev')
+ .describe('Start a development server')
+ .option('-p, --port', 'Specify a port')
+ .action(async (opts: { port: number }) => {
+ const { dev } = await import('./cli/dev');
+ dev(opts);
+ });
+
+prog.command('build [dest]')
+ .describe('Create a production-ready version of your app')
+ .action(async (dest = 'build') => {
+ console.log(`> Building...`);
+
+ process.env.NODE_ENV = 'production';
+ process.env.SAPPER_DEST = dest;
+
+ const start = Date.now();
+
+ try {
+ const { build } = await import('./cli/build');
+ await build();
+ console.error(`\n> Finished in ${elapsed(start)}. Type ${clorox.bold.cyan(dest === 'build' ? 'npx sapper start' : `npx sapper start ${dest}`)} to run the app.`);
+ } catch (err) {
+ console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
+ }
+ });
+
+prog.command('start [dir]')
+ .describe('Start your app')
+ .option('-p, --port', 'Specify a port')
+ .action(async (dir = 'build', opts: { port: number }) => {
+ const { start } = await import('./cli/start');
+ start(dir, opts);
+ });
+
+prog.command('export [dest]')
+ .describe('Export your app as static files (if possible)')
+ .action(async (dest = 'export') => {
+ console.log(`> Building...`);
+
+ process.env.NODE_ENV = 'production';
+ process.env.SAPPER_DEST = '.sapper/.export';
+
+ const start = Date.now();
+
+ try {
+ const { build } = await import('./cli/build');
+ await build();
+ console.error(`\n> Built in ${elapsed(start)}. Exporting...`);
+
+ const { exporter } = await import('./cli/export');
+ await exporter(dest);
+ console.error(`\n> Finished in ${elapsed(start)}. Type ${clorox.bold.cyan(`npx serve ${dest}`)} to run the app.`);
+ } catch (err) {
+ console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
+ }
+ });
+
+// TODO upgrade
+
+prog.parse(process.argv);
+
+function elapsed(start: number) {
+ return prettyMs(Date.now() - start);
+}
\ No newline at end of file
diff --git a/src/cli/build.ts b/src/cli/build.ts
index f71b06e..c599594 100644
--- a/src/cli/build.ts
+++ b/src/cli/build.ts
@@ -3,10 +3,10 @@ import * as path from 'path';
import * as clorox from 'clorox';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
-import { create_compilers, create_app, create_routes, create_serviceworker } from 'sapper/core.js'
+import { create_compilers, create_app, create_routes, create_serviceworker } from '../core'
import { src, dest, dev } from '../config';
-export default async function build() {
+export async function build() {
const output = dest();
mkdirp.sync(output);
@@ -20,12 +20,12 @@ export default async function build() {
const { client, server, serviceworker } = create_compilers();
const client_stats = await compile(client);
- console.log(clorox.inverse(`\nbuilt client`));
+ console.log(clorox.inverse(`\nbuilt client`).toString());
console.log(client_stats.toString({ colors: true }));
fs.writeFileSync(path.join(output, 'client_info.json'), JSON.stringify(client_stats.toJson()));
const server_stats = await compile(server);
- console.log(clorox.inverse(`\nbuilt server`));
+ console.log(clorox.inverse(`\nbuilt server`).toString());
console.log(server_stats.toString({ colors: true }));
let serviceworker_stats;
@@ -38,7 +38,7 @@ export default async function build() {
});
serviceworker_stats = await compile(serviceworker);
- console.log(clorox.inverse(`\nbuilt service worker`));
+ console.log(clorox.inverse(`\nbuilt service worker`).toString());
console.log(serviceworker_stats.toString({ colors: true }));
}
}
diff --git a/src/cli/dev.ts b/src/cli/dev.ts
index 2313479..99f9a9f 100644
--- a/src/cli/dev.ts
+++ b/src/cli/dev.ts
@@ -10,7 +10,7 @@ import format_messages from 'webpack-format-messages';
import prettyMs from 'pretty-ms';
import * as ports from 'port-authority';
import { dest } from '../config';
-import { create_compilers, create_app, create_routes, create_serviceworker } from 'sapper/core.js';
+import { create_compilers, create_app, create_routes, create_serviceworker } from '../core';
type Deferred = {
promise?: Promise;
@@ -70,9 +70,20 @@ function create_hot_update_server(port: number, interval = 10000) {
return { send };
}
-export default async function dev(port: number) {
+export async function dev(opts: { port: number }) {
process.env.NODE_ENV = 'development';
+ let port = opts.port || +process.env.PORT;
+
+ if (port) {
+ if (!await ports.check(port)) {
+ console.log(clorox.bold.red(`> Port ${port} is unavailable`));
+ return;
+ }
+ } else {
+ port = await ports.find(3000);
+ }
+
const dir = dest();
rimraf.sync(dir);
mkdirp.sync(dir);
diff --git a/src/cli/export.ts b/src/cli/export.ts
index 6dcf9d3..8e4598a 100644
--- a/src/cli/export.ts
+++ b/src/cli/export.ts
@@ -10,7 +10,7 @@ import { dest } from '../config';
const app = polka();
-export default async function exporter(export_dir: string) {
+export async function exporter(export_dir: string) {
const build_dir = dest();
// Prep output directory
diff --git a/src/cli/index.ts b/src/cli/index.ts
deleted file mode 100755
index f6678ed..0000000
--- a/src/cli/index.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import * as fs from 'fs';
-import * as path from 'path';
-import * as child_process from 'child_process';
-import sade from 'sade';
-import * as clorox from 'clorox';
-import prettyMs from 'pretty-ms';
-import help from './help.md';
-import build from './build';
-import exporter from './export';
-import dev from './dev';
-import upgrade from './upgrade';
-import * as ports from 'port-authority';
-import * as pkg from '../../package.json';
-
-const prog = sade('sapper').version(pkg.version);
-
-prog.command('dev')
- .describe('Start a development server')
- .option('-p, --port', 'Specify a port')
- .action(async (opts: { port: number }) => {
- let port = opts.port || +process.env.PORT;
-
- if (port) {
- if (!await ports.check(port)) {
- console.log(clorox.bold.red(`> Port ${port} is unavailable`));
- return;
- }
- } else {
- port = await ports.find(3000);
- }
-
- dev(port);
- });
-
-prog.command('build [dest]')
- .describe('Create a production-ready version of your app')
- .action((dest = 'build') => {
- console.log(`> Building...`);
-
- process.env.NODE_ENV = 'production';
- process.env.SAPPER_DEST = dest;
-
- const start = Date.now();
-
- build()
- .then(() => {
- const elapsed = Date.now() - start;
- console.error(`\n> Finished in ${prettyMs(elapsed)}. Type ${clorox.bold.cyan(dest === 'build' ? 'npx sapper start' : `npx sapper start ${dest}`)} to run the app.`);
- })
- .catch(err => {
- console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
- });
- });
-
-prog.command('start [dir]')
- .describe('Start your app')
- .option('-p, --port', 'Specify a port')
- .action(async (dir = 'build', opts: { port: number }) => {
- let port = opts.port || +process.env.PORT;
-
- const resolved = path.resolve(dir);
- const server = path.resolve(dir, 'server.js');
-
- if (!fs.existsSync(server)) {
- console.log(clorox.bold.red(`> ${dir}/server.js does not exist — type ${clorox.bold.cyan(dir === 'build' ? `npx sapper build` : `npx sapper build ${dir}`)} to create it`));
- return;
- }
-
- if (port) {
- if (!await ports.check(port)) {
- console.log(clorox.bold.red(`> Port ${port} is unavailable`));
- return;
- }
- } else {
- port = await ports.find(3000);
- }
-
- child_process.fork(server, [], {
- cwd: process.cwd(),
- env: Object.assign({
- NODE_ENV: 'production',
- PORT: port,
- SAPPER_DEST: dir
- }, process.env)
- });
- });
-
-prog.command('export [dest]')
- .describe('Export your app as static files (if possible)')
- .action((dest = 'export') => {
- console.log(`> Building...`);
-
- process.env.NODE_ENV = 'production';
- process.env.SAPPER_DEST = '.sapper/.export';
-
- const start = Date.now();
-
- build()
- .then(() => {
- const elapsed = Date.now() - start;
- console.error(`\n> Built in ${prettyMs(elapsed)}. Exporting...`);
- })
- .then(() => exporter(dest))
- .then(() => {
- const elapsed = Date.now() - start;
- console.error(`\n> Finished in ${prettyMs(elapsed)}. Type ${clorox.bold.cyan(`npx serve ${dest}`)} to run the app.`);
- })
- .catch(err => {
- console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
- });
- });
-
-// TODO upgrade
-
-prog.parse(process.argv);
diff --git a/src/cli/start.ts b/src/cli/start.ts
new file mode 100644
index 0000000..ffb1ec8
--- /dev/null
+++ b/src/cli/start.ts
@@ -0,0 +1,35 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import * as child_process from 'child_process';
+import * as clorox from 'clorox';
+import * as ports from 'port-authority';
+
+export async function start(dir: string, opts: { port: number }) {
+ let port = opts.port || +process.env.PORT;
+
+ const resolved = path.resolve(dir);
+ const server = path.resolve(dir, 'server.js');
+
+ if (!fs.existsSync(server)) {
+ console.log(clorox.bold.red(`> ${dir}/server.js does not exist — type ${clorox.bold.cyan(dir === 'build' ? `npx sapper build` : `npx sapper build ${dir}`)} to create it`));
+ return;
+ }
+
+ if (port) {
+ if (!await ports.check(port)) {
+ console.log(clorox.bold.red(`> Port ${port} is unavailable`));
+ return;
+ }
+ } else {
+ port = await ports.find(3000);
+ }
+
+ child_process.fork(server, [], {
+ cwd: process.cwd(),
+ env: Object.assign({
+ NODE_ENV: 'production',
+ PORT: port,
+ SAPPER_DEST: dir
+ }, process.env)
+ });
+}
\ No newline at end of file
diff --git a/src/core.ts b/src/core.ts
new file mode 100644
index 0000000..d6c2400
--- /dev/null
+++ b/src/core.ts
@@ -0,0 +1,4 @@
+export { default as create_app } from './core/create_app';
+export { default as create_serviceworker } from './core/create_serviceworker';
+export { default as create_compilers } from './core/create_compilers';
+export { default as create_routes } from './core/create_routes';
\ No newline at end of file
diff --git a/src/core/index.ts b/src/core/index.ts
deleted file mode 100644
index 80b7812..0000000
--- a/src/core/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { default as create_app } from './create_app';
-export { default as create_serviceworker } from './create_serviceworker';
-export { default as create_compilers } from './create_compilers';
-export { default as create_routes } from './create_routes';
\ No newline at end of file
diff --git a/src/middleware/index.ts b/src/middleware.ts
similarity index 97%
rename from src/middleware/index.ts
rename to src/middleware.ts
index ebe0db3..6aa9e5e 100644
--- a/src/middleware/index.ts
+++ b/src/middleware.ts
@@ -4,10 +4,10 @@ import { ClientRequest, ServerResponse } from 'http';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import devalue from 'devalue';
-import { lookup } from './mime';
-import { create_routes, templates, create_compilers } from 'sapper/core.js';
-import { dest, dev } from '../config';
-import { Route, Template } from '../interfaces';
+import { lookup } from './middleware/mime';
+import { create_routes, templates, create_compilers } from './core/index';
+import { dest, dev } from './config';
+import { Route, Template } from './interfaces';
import sourceMapSupport from 'source-map-support';
sourceMapSupport.install();
diff --git a/src/webpack/index.ts b/src/webpack.ts
similarity index 95%
rename from src/webpack/index.ts
rename to src/webpack.ts
index 5b29992..7fd3e86 100644
--- a/src/webpack/index.ts
+++ b/src/webpack.ts
@@ -1,4 +1,4 @@
-import { dest, dev } from '../config';
+import { dest, dev } from './config';
export default {
dev: dev(),
diff --git a/test/common/test.js b/test/common/test.js
index f825e84..e40c87b 100644
--- a/test/common/test.js
+++ b/test/common/test.js
@@ -25,7 +25,7 @@ Nightmare.action('prefetchRoutes', function(done) {
this.evaluate_now(() => window.prefetchRoutes(), done);
});
-const cli = path.resolve(__dirname, '../../cli.js');
+const cli = path.resolve(__dirname, '../../sapper');
describe('sapper', function() {
process.chdir(path.resolve(__dirname, '../app'));
diff --git a/test/unit/create_routes.test.js b/test/unit/create_routes.test.js
index a58b626..50924dd 100644
--- a/test/unit/create_routes.test.js
+++ b/test/unit/create_routes.test.js
@@ -1,5 +1,5 @@
const assert = require('assert');
-const { create_routes } = require('../../core.js');
+const { create_routes } = require('../../core.ts.js');
describe('create_routes', () => {
it('sorts routes correctly', () => {
diff --git a/webpack.js b/webpack.js
new file mode 100644
index 0000000..38e44b8
--- /dev/null
+++ b/webpack.js
@@ -0,0 +1,2 @@
+// TODO write to this file, instead of webpack.ts.js
+module.exports = require('./webpack.ts.js');
\ No newline at end of file
diff --git a/webpack/config.js b/webpack/config.js
new file mode 100644
index 0000000..9e50d96
--- /dev/null
+++ b/webpack/config.js
@@ -0,0 +1,2 @@
+// TODO deprecate this file in favour of sapper/webpack.js
+module.exports = require('../webpack.ts.js');
\ No newline at end of file