marko/node-require.js

144 lines
4.9 KiB
JavaScript

'use strict';
require('./runtime/env-init');
const path = require('path');
const resolveFrom = require('resolve-from');
const fs = require('fs');
const fsReadOptions = { encoding: 'utf8' };
const MARKO_EXTENSIONS = Symbol('MARKO_EXTENSIONS');
function normalizeExtension(extension) {
if (extension.charAt(0) !== '.') {
extension = '.' + extension;
}
return extension;
}
function compile(templatePath, markoCompiler, compilerOptions) {
if (compilerOptions) {
compilerOptions = Object.assign({}, markoCompiler.defaultOptions, compilerOptions);
} else {
compilerOptions = markoCompiler.defaultOptions;
}
var writeToDisk = compilerOptions.writeToDisk;
var templateSrc;
var compiledSrc;
if (writeToDisk === false) {
// Don't write the compiled template to disk. Instead, load it
// directly from the compiled source using the internals of the
// Node.js module loading system.
templateSrc = fs.readFileSync(templatePath, fsReadOptions);
compiledSrc = markoCompiler.compile(templateSrc, templatePath);
} else {
var targetFile = templatePath + '.js';
if (markoCompiler.defaultOptions.assumeUpToDate && fs.existsSync(targetFile)) {
// If the target file already exists and "assumeUpToDate" then just use the previously
// compiled template.
return fs.readFileSync(targetFile, fsReadOptions);
}
var targetDir = path.dirname(templatePath);
var isUpToDate = markoCompiler.checkUpToDate(targetFile);
if (isUpToDate) {
compiledSrc = fs.readFileSync(targetFile, fsReadOptions);
} else {
templateSrc = fs.readFileSync(templatePath, fsReadOptions);
compiledSrc = markoCompiler.compile(templateSrc, templatePath, compilerOptions);
// Write to a temporary file and move it into place to avoid problems
// assocatiated with multiple processes write to the same file. We only
// write the compiled source code to disk so that stack traces will
// be accurate.
var filename = path.basename(targetFile);
var tempFile = path.join(targetDir, '.' + process.pid + '.' + Date.now() + '.' + filename);
fs.writeFileSync(tempFile, compiledSrc, fsReadOptions);
fs.renameSync(tempFile, targetFile);
}
}
// We attach a path to the compiled template so that hot reloading will work.
return compiledSrc;
}
function getLoadedTemplate(path) {
var cached = require.cache[path];
return cached && cached.exports.render ? cached.exports : undefined;
}
function install(options) {
options = options || {};
var requireExtensions = options.require ? // options.require introduced for testing
options.require.extensions :
require.extensions;
var compilerOptions = options.compilerOptions;
if (compilerOptions) {
require('./compiler').configure(compilerOptions);
} else {
compilerOptions = {};
}
var extensions = [];
if (options.extension) {
extensions.push(options.extension);
}
if (options.extensions) {
extensions = extensions.concat(options.extensions);
}
if (extensions.length === 0) {
extensions.push('.marko');
}
function markoRequireExtension(module, filename) {
var targetFile = filename + '.js';
var cachedTemplate = getLoadedTemplate(targetFile) || getLoadedTemplate(filename);
if (cachedTemplate) {
// The template has already been loaded so use the exports of the already loaded template
module.exports = cachedTemplate;
return;
}
// Resolve the appropriate compiler relative to the location of the
// marko template file on disk using the "resolve-from" module.
var dirname = path.dirname(filename);
var markoCompilerModulePath = resolveFrom(dirname, 'marko/compiler');
var markoCompiler = require(markoCompilerModulePath);
// Now use the appropriate Marko compiler to compile the Marko template
// file to JavaScript source code:
var compiledSrc = compile(filename, markoCompiler, compilerOptions);
// Append ".js" to the filename since that is where we write the compiled
// source code that is being loaded. This allows stack traces to match up.
module._compile(compiledSrc, targetFile);
}
requireExtensions[MARKO_EXTENSIONS] = requireExtensions[MARKO_EXTENSIONS] ||
(requireExtensions[MARKO_EXTENSIONS] = []);
extensions.forEach((extension) => {
extension = normalizeExtension(extension);
requireExtensions[extension] = markoRequireExtension;
requireExtensions[MARKO_EXTENSIONS].push(extension);
});
}
install();
exports.install = install;
exports.getExtensions = function() {
return require.extensions[MARKO_EXTENSIONS];
};