function contentRollupPlugin({ root }) {
	return {
		name: 'content',
		async resolveId(id, importer) {
			if (id[0] === '\0' || !id.startsWith('content:')) return;
			id = id.slice(8);
			if (importer) importer = importer.replace(/^[\0\b]\w+:/g, '');
			let resolved = await this.resolve(id, importer, { skipSelf: true });
			if (!resolved) {
				const r = path.join(path.dirname(importer), id);
				const s = await fs.stat(r).catch(() => null);
				if (s && s.isDirectory()) resolved = { id: r };
			}
			if (resolved) return '\0content:' + resolved.id.replace(/\/\.$/, '');
		},
		async load(id) {
			if (!id.startsWith('\0content:')) return;
			id = path.resolve(root, id.slice(9));
			const files = (await tree(id)).filter(file => file.endsWith('.md'));
			const dirs = path.relative(root, id).split(path.sep);
			const config = (
				await Promise.all(
					dirs.map(async (d, i, dirs) => {
						try {
							return yaml.parse(await fs.readFile(path.resolve(root, ...dirs.slice(0, i), '_config.yml'), 'utf-8'));
						} catch (e) {}
					})
				)
			).reduce(merge, {});
			function merge(obj, props) {
				if (props == null) return obj;
				if (typeof props === 'object') {
					for (let i in props) {
						obj[i] = obj[i] ? merge(obj[i], props[i]) : props[i];
					}
					return obj;
				}
				return props;
			}
			const byName = new Map();
			let data = await Promise.all(
				files.map(async file => {
					const { slug, ...meta } = await getMeta(path.resolve(id, file));
					const item = { name: slug || file.replace(/\.md$/, ''), ...meta };
					byName.set(item.name, item);
					return item;
				})
			);
			const collection = path.basename(id);
			const cfg = config.collections[collection];
			let sortBy = 'published';
			if (cfg) {
				if (cfg.order) {
					data = cfg.order.map(item => {
						if (typeof item === 'string') return byName.get(item);
						return item;
					});
				} else if (cfg.sort_by) {
					sortBy = cfg.sort_by;
				}
			}
			// detect and convert string dates and numbers to Date and Number for sorting
			const parse = field => {
				let d = Date.parse(field);
				if (!isNaN(d)) return d;
				d = Number(field);
				if (d == field) return d;
				return field;
			};
			data.sort((a, b) => parse(b[sortBy]) - parse(a[sortBy]));

			let imports = '';

			const serializeItem = item => {
				if (item.name) {
					const url = 'markdown:./' + path.posix.relative(path.dirname(id), path.resolve(id, item.name)) + '.md';
					imports += `import ${JSON.stringify(url)};\n`;
				}

				let str = '{ ';
				for (let i in item) if (item[i] != null) str += `${i}: ${JSON.stringify(item[i])}, `;
				return str + '}';
			};

			const code = 'export default [' + data.map(serializeItem).join(',\n') + '];';
			return imports + code;
		}
	};
}
markdown blog/content plugin for Rollup / WMR