move files around

This commit is contained in:
Rich Harris
2017-12-15 14:46:23 -05:00
parent f5a19ef34b
commit e810ead93f
6 changed files with 7 additions and 7 deletions

26
lib/utils/create_app.js Normal file
View File

@@ -0,0 +1,26 @@
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.resolve(__dirname, '../../templates/main.js'), 'utf-8');
module.exports = function create_app(src, dest, routes, options) {
// TODO in dev mode, watch files
const code = routes
.filter(route => route.type === 'page')
.map(route => {
const params = route.dynamic.length === 0 ?
'{}' :
`{ ${route.dynamic.map((part, i) => `${part}: match[${i + 1}]`).join(', ') } }`;
return `{ pattern: ${route.pattern}, params: match => (${params}), load: () => import('${src}/${route.file}') }`
})
.join(',\n\t');
const main = template
.replace('__app__', path.resolve(__dirname, '../../runtime/app.js'))
.replace('__selector__', options.selector || 'main')
.replace('__routes__', code);
fs.writeFileSync(path.join(dest, 'main.js'), main);
};

View File

@@ -0,0 +1,53 @@
const path = require('path');
module.exports = function create_matchers(files) {
return files
.map(file => {
if (/(^|\/|\\)_/.test(file)) return;
const parts = file.replace(/\.(html|js|mjs)$/, '').split(path.sep);
if (parts[parts.length - 1] === 'index') parts.pop();
const id = parts.join('_').replace(/[[\]]/g, '$') || '_';
const dynamic = parts
.filter(part => part[0] === '[')
.map(part => part.slice(1, -1));
const pattern = new RegExp(
`^\\/${parts.map(p => p[0] === '[' ? '([^/]+)' : p).join('\\/')}$`
);
const test = url => pattern.test(url);
const exec = url => {
const match = pattern.exec(url);
if (!match) return;
const params = {};
dynamic.forEach((param, i) => {
params[param] = match[i + 1];
});
return params;
};
return {
id,
type: path.extname(file) === '.html' ? 'page' : 'route',
file,
pattern,
test,
exec,
parts,
dynamic
};
})
.filter(Boolean)
.sort((a, b) => {
return (
(a.dynamic.length - b.dynamic.length) || // match static paths first
(b.parts.length - a.parts.length) // match longer paths first
);
});
}

View File

@@ -0,0 +1,51 @@
const path = require('path');
const assert = require('assert');
const create_matchers = require('./create_matchers.js');
describe('create_matchers', () => {
it('sorts routes correctly', () => {
const matchers = create_matchers(['index.html', 'about.html', '[wildcard].html', 'post/[id].html']);
assert.deepEqual(
matchers.map(m => m.file),
[
'about.html',
'index.html',
'post/[id].html',
'[wildcard].html'
]
);
});
it('generates params', () => {
const matchers = create_matchers(['index.html', 'about.html', '[wildcard].html', 'post/[id].html']);
let file;
let params;
for (let i = 0; i < matchers.length; i += 1) {
const matcher = matchers[i];
if (params = matcher.exec('/post/123')) {
file = matcher.file;
break;
}
}
assert.equal(file, 'post/[id].html');
assert.deepEqual(params, {
id: '123'
});
});
it('ignores files and directories with leading underscores', () => {
const matches = create_matchers(['index.html', '_foo.html', 'a/_b/c/d.html', 'e/f/g/h.html', 'i/_j.html']);
assert.deepEqual(
matches.map(m => m.file),
[
'e/f/g/h.html',
'index.html'
]
);
});
});

View File

@@ -0,0 +1,100 @@
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const templates = require('../templates.js');
module.exports = function create_webpack_compiler(dest, routes, dev) {
const compiler = {};
const client = webpack(
require(path.resolve('webpack.client.config.js'))
);
const server = webpack(
require(path.resolve('webpack.server.config.js'))
);
if (false) { // TODO watch in dev
// TODO how can we invalidate compiler.client_main when watcher restarts?
compiler.client_main = new Promise((fulfil, reject) => {
client.watch({}, (err, stats) => {
if (err || stats.hasErrors()) {
// TODO handle errors
}
const filename = stats.toJson().assetsByChunkName.main;
fulfil(`/client/${filename}`);
});
});
// TODO server
} else {
compiler.ready = Promise.all([
new Promise((fulfil, reject) => {
client.run((err, stats) => {
console.log(stats.toString({ colors: true }));
const info = stats.toJson();
if (err || stats.hasErrors()) {
reject(err || info.errors[0]);
}
compiler.client_main = `/client/${info.assetsByChunkName.main}`;
compiler.assets = info.assets.map(asset => `/client/${asset.name}`);
fulfil();
});
}),
new Promise((fulfil, reject) => {
server.run((err, stats) => {
console.log(stats.toString({ colors: true }));
const info = stats.toJson();
if (err || stats.hasErrors()) {
reject(err || info.errors[0]);
}
compiler.chunks = info.assetsByChunkName;
fulfil();
});
})
]).then(() => {
const assets = glob.sync('**', { cwd: 'assets' });
const route_code = `[${
routes
.filter(route => route.type === 'page')
.map(route => `{ pattern: ${route.pattern} }`)
.join(', ')
}]`;
const service_worker = fs.readFileSync('templates/service-worker.js', 'utf-8')
.replace('__timestamp__', Date.now())
.replace('__assets__', JSON.stringify(assets))
.replace('__shell__', JSON.stringify(compiler.assets.concat('/index.html')))
.replace('__routes__', route_code);
fs.writeFileSync(path.resolve(dest, 'service-worker.js'), service_worker);
const shell = templates.render(200, {
styles: '',
head: '',
html: '',
main: compiler.client_main
});
fs.writeFileSync(path.resolve(dest, 'index.html'), shell);
});
compiler.get_chunk = async id => {
return path.resolve(dest, 'server', compiler.chunks[id]);
};
}
return compiler;
};