mailor
Version:
Low-cost mailing authoring
223 lines (181 loc) • 6.33 kB
JavaScript
const glob = require('glob');
const chokidar = require('chokidar');
const {
readdirSync, readFileSync, existsSync,
} = require('fs');
const {
join, resolve, relative, basename, dirname,
} = require('path');
const Mailer = require('../lib/mailer');
const { toArray, fetchTags } = require('./util');
module.exports = async (templates, opts) => {
async function run(srcFiles) {
try {
await require('../lib/compiler')(srcFiles, opts);
} catch (e) {
process.stderr.write(`\x1b[31m${e.message}\x1b[0m\n`);
}
}
/* istanbul ignore else */
if (opts.build !== false) {
await run(templates);
}
let files = [];
let interval;
function update() {
clearTimeout(interval);
interval = setTimeout(async () => {
await run(files);
files = [];
}, opts.timeout || 200);
}
const watching = toArray(opts.watch);
const sources = opts.srcDir
.reduce((prev, cur) => prev.concat(cur.includes('*') ? glob.sync(cur) : cur), [])
.concat(watching.map(x => resolve(x)));
process.stdout.write(`\rWatching: ${sources.map(x => relative(opts.cwd, x)).join(', ')}\n`);
const watcher = chokidar.watch(sources, {
ignored: /(^|[/\\])\../,
ignoreInitial: false,
persistent: true,
});
watcher
.on('all', (type, file) => {
const src = relative(opts.cwd, file);
/* istanbul ignore else */
if (existsSync(file) && type !== 'addDir' && (!watching.some(dir => src.indexOf(dir) === 0))) {
/* istanbul ignore else */
if (type === 'add' && src.includes('.pug') && !templates.includes(file)) {
templates.push(file);
}
/* istanbul ignore else */
if ((!files.includes(file) && type === 'add') || type === 'change') {
/* istanbul ignore else */
if (type === 'add') process.stdout.write(`Added ${src}\n`);
files.push(file);
update();
}
} else if (templates.includes(file)) {
templates = templates.filter(x => x !== file);
process.stdout.write(`Removed ${src}\n`);
}
});
const liveServer = require('live-server');
const publicDir = resolve(__dirname, '../public');
const devPort = opts.port || process.env.PORT || 1081;
const watchingDirs = [opts.destDir, publicDir]
.concat(opts.jsonfile ? opts.jsonfile : []);
let maildev;
liveServer.start({
logLevel: 0,
cors: true,
port: devPort,
root: publicDir,
watch: watchingDirs,
open: opts.open !== false,
ignore: 'generated_templates',
mount: [
['/vendor', resolve(__dirname, '../dist')],
],
middleware: [(req, res, next) => {
/* istanbul ignore else */
if (req.url.indexOf('/generated_templates/') === 0) {
const [base, query] = req.url.substr(21).split('?');
let data;
try {
data = JSON.parse(decodeURIComponent(query));
} catch (e) {
// ignore
}
Mailer.render(join(opts.destDir, `${base}.${opts.extname}`), data || {})
.catch(e => e.message)
.then(x => res.end(x));
return;
}
/* istanbul ignore else */
if (req.url.indexOf('/send_template/') === 0) {
const [base, query] = req.url.substr(15).split('?');
const parts = query.split(',');
let data = {};
try {
data = JSON.parse(decodeURIComponent(parts.pop()));
} catch (e) {
// ignore
}
require('./send')([join(opts.destDir, `${base}.${opts.extname}`)], {
subject: `[TEST] ${base}`,
address: parts.join(','),
locals: data,
}).then(() => {
res.end(`Email was successfully sent to: ${parts.join(', ')}`);
}).catch(e => {
res.end(e.message);
});
return;
}
/* istanbul ignore else */
if (req.url.indexOf('/recipients.json') === 0) {
if (req.method === 'DELETE') {
const emailId = req.url.split('?')[1];
if (emailId) {
maildev.deleteEmail(emailId, () => res.end(`The email ${emailId} was deleted`));
} else {
maildev.deleteAllEmail(() => res.end('All email was deleted successfully'));
}
} else {
res.setHeader('content-type', 'application/json');
maildev.getAllEmail((err, emails) => {
res.end(JSON.stringify(emails.reverse()));
});
}
return;
}
/* istanbul ignore else */
if (req.url === '/variables.json') {
res.setHeader('content-type', 'application/json');
res.end(JSON.stringify(readdirSync(opts.destDir).reduce((prev, cur) => {
const fileContent = readFileSync(join(opts.destDir, cur)).toString();
prev[cur.replace(`.${opts.extname}`, '')] = fetchTags(fileContent);
return prev;
}, {})));
return;
}
/* istanbul ignore else */
if (req.url === '/templates.json') {
res.setHeader('content-type', 'application/json');
res.end(JSON.stringify(templates.filter(src => {
return src.includes('.pug') && basename(src).charAt() !== '_' && dirname(src).charAt() !== '_';
}).map(x => basename(x, '.pug'))));
return;
}
/* istanbul ignore else */
if (req.url === '/defaults.json') {
const srcFile = resolve(opts.jsonfile || 'defaults.json');
delete require.cache[srcFile];
res.setHeader('content-type', 'application/json');
/* istanbul ignore else */
if (!existsSync(srcFile)) {
res.end('{}');
return;
}
const check = require(srcFile);
Promise.resolve()
.then(() => (typeof check === 'function' ? check() : check))
.then(result => res.end(JSON.stringify(result)))
.catch(() => res.end('{}'));
}
next();
}],
});
process.stdout.write(`\rPreview your email templates at http://0.0.0.0:${devPort}\n`); // eslint-disable-line
/* istanbul ignore else */
if (opts.server !== false) {
maildev = require('../lib/maildev')(opts.relayOptions, opts.noFormat);
maildev.listen();
}
process.on('exit', () => {
liveServer.shutdown();
/* istanbul ignore else */
if (maildev) maildev.close();
});
};