diff --git a/hot-reload/index.js b/hot-reload/index.js index 7d46054fb..0d1885822 100644 --- a/hot-reload/index.js +++ b/hot-reload/index.js @@ -2,6 +2,7 @@ require('raptor-polyfill/string/endsWith'); const nodePath = require('path'); const fs = require('fs'); +const nodeRequire = require('../node-require'); var compiler; var marko; @@ -11,7 +12,6 @@ var widgets; var modifiedId = 1; var HOT_RELOAD_KEY = Symbol('HOT_RELOAD'); - function cleaResolvePathCache() { var modulePathCache = require('module').Module._pathCache; if (!modulePathCache) { @@ -105,12 +105,53 @@ exports.enable = function() { }; }; -exports.handleFileModified = function(path) { +/** + * Checks whether a path ends with a custom Marko extension + */ +function _endsWithMarkoExtension(path, requireExtensions) { + for (var i = 0; i < requireExtensions.length; i++) { + if (path.endsWith(requireExtensions[i])) { + return true; + } + } + return false; +} + +function normalizeExtension(extension) { + if (extension.charAt(0) !== '.') { + extension = '.' + extension; + } + return extension; +} + +exports.handleFileModified = function(path, options) { if (!fs.existsSync(path)) { console.log('[marko/hot-reload] WARNING cannot resolve template path: ', path); return; } + options = options || {}; + + // Default hot-reloaded extensions + var requireExtensions = ['.marko', '.marko.html', '.marko.xml']; + + if (options.extension) { + requireExtensions.push(options.extension); + } + + if (options.extensions) { + requireExtensions = requireExtensions.concat(options.extensions); + } + + var nodeRequireExtensions = nodeRequire.getExtensions(); + if (nodeRequireExtensions) { + requireExtensions = requireExtensions.concat(nodeRequireExtensions); + } + + for (var i = 0; i < requireExtensions.length; i++) { + requireExtensions[i] = normalizeExtension(requireExtensions[i]); + } + var basename = nodePath.basename(path); function handleFileModified() { @@ -130,7 +171,7 @@ exports.handleFileModified = function(path) { delete require.cache[filename]; } }); - } else if (path.endsWith('.marko') || path.endsWith('.marko.html') || path.endsWith('.marko.xml')) { + } else if (_endsWithMarkoExtension(path, requireExtensions)) { handleFileModified(); delete require.cache[path]; delete require.cache[path + '.js']; diff --git a/node-require.js b/node-require.js index 706d234a6..698dba05c 100644 --- a/node-require.js +++ b/node-require.js @@ -5,6 +5,7 @@ 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) !== '.') { @@ -123,12 +124,20 @@ function install(options) { 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]; +}; diff --git a/test/autotests/hot-reload/require-custom-extension/.gitignore b/test/autotests/hot-reload/require-custom-extension/.gitignore new file mode 100644 index 000000000..94bf82e3f --- /dev/null +++ b/test/autotests/hot-reload/require-custom-extension/.gitignore @@ -0,0 +1 @@ +template.temp* \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-extension/template.html b/test/autotests/hot-reload/require-custom-extension/template.html new file mode 100644 index 000000000..4b6673751 --- /dev/null +++ b/test/autotests/hot-reload/require-custom-extension/template.html @@ -0,0 +1 @@ +-- Hello ${data.name}! \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-extension/test.js b/test/autotests/hot-reload/require-custom-extension/test.js new file mode 100644 index 000000000..d3416e4ad --- /dev/null +++ b/test/autotests/hot-reload/require-custom-extension/test.js @@ -0,0 +1,24 @@ +var fs = require('fs'); +var nodePath = require('path'); + +exports.check = function(marko, hotReload, expect) { + var srcTemplatePath = nodePath.join(__dirname, 'template.html'); + var templateSrc = fs.readFileSync(srcTemplatePath, { encoding: 'utf8' }); + + var tempTemplatePath = nodePath.join(__dirname, 'template.temp.html'); + fs.writeFileSync(tempTemplatePath, templateSrc, { encoding: 'utf8' }); + + var template = marko.load(tempTemplatePath); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + fs.writeFileSync(tempTemplatePath, templateSrc + '!', { encoding: 'utf8' }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + hotReload.handleFileModified(tempTemplatePath, { + extension: '.html' + }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!!'); +}; \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-multiple-extensions/.gitignore b/test/autotests/hot-reload/require-custom-multiple-extensions/.gitignore new file mode 100644 index 000000000..94bf82e3f --- /dev/null +++ b/test/autotests/hot-reload/require-custom-multiple-extensions/.gitignore @@ -0,0 +1 @@ +template.temp* \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-multiple-extensions/template.html b/test/autotests/hot-reload/require-custom-multiple-extensions/template.html new file mode 100644 index 000000000..4b6673751 --- /dev/null +++ b/test/autotests/hot-reload/require-custom-multiple-extensions/template.html @@ -0,0 +1 @@ +-- Hello ${data.name}! \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-multiple-extensions/test.js b/test/autotests/hot-reload/require-custom-multiple-extensions/test.js new file mode 100644 index 000000000..1390afa48 --- /dev/null +++ b/test/autotests/hot-reload/require-custom-multiple-extensions/test.js @@ -0,0 +1,24 @@ +var fs = require('fs'); +var nodePath = require('path'); + +exports.check = function(marko, hotReload, expect) { + var srcTemplatePath = nodePath.join(__dirname, 'template.html'); + var templateSrc = fs.readFileSync(srcTemplatePath, { encoding: 'utf8' }); + + var tempTemplatePath = nodePath.join(__dirname, 'template.temp.html'); + fs.writeFileSync(tempTemplatePath, templateSrc, { encoding: 'utf8' }); + + var template = marko.load(tempTemplatePath); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + fs.writeFileSync(tempTemplatePath, templateSrc + '!', { encoding: 'utf8' }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + hotReload.handleFileModified(tempTemplatePath, { + extensions: ['.html'] + }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!!'); +}; \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-without-period/.gitignore b/test/autotests/hot-reload/require-custom-without-period/.gitignore new file mode 100644 index 000000000..94bf82e3f --- /dev/null +++ b/test/autotests/hot-reload/require-custom-without-period/.gitignore @@ -0,0 +1 @@ +template.temp* \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-without-period/template.html b/test/autotests/hot-reload/require-custom-without-period/template.html new file mode 100644 index 000000000..4b6673751 --- /dev/null +++ b/test/autotests/hot-reload/require-custom-without-period/template.html @@ -0,0 +1 @@ +-- Hello ${data.name}! \ No newline at end of file diff --git a/test/autotests/hot-reload/require-custom-without-period/test.js b/test/autotests/hot-reload/require-custom-without-period/test.js new file mode 100644 index 000000000..6e49a543b --- /dev/null +++ b/test/autotests/hot-reload/require-custom-without-period/test.js @@ -0,0 +1,24 @@ +var fs = require('fs'); +var nodePath = require('path'); + +exports.check = function(marko, hotReload, expect) { + var srcTemplatePath = nodePath.join(__dirname, 'template.html'); + var templateSrc = fs.readFileSync(srcTemplatePath, { encoding: 'utf8' }); + + var tempTemplatePath = nodePath.join(__dirname, 'template.temp.html'); + fs.writeFileSync(tempTemplatePath, templateSrc, { encoding: 'utf8' }); + + var template = marko.load(tempTemplatePath); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + fs.writeFileSync(tempTemplatePath, templateSrc + '!', { encoding: 'utf8' }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!'); + + hotReload.handleFileModified(tempTemplatePath, { + extensions: ['html'] + }); + + expect(template.renderSync({ name: 'John' }).toString()).to.equal('Hello John!!'); +}; \ No newline at end of file