From 05b68391ddacb92719fd19b1013d1d813ce50a40 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 14 Jan 2017 22:36:10 -0700 Subject: [PATCH] Use `/assets` for client assets - Route `/assets` -> `build/public`, falling back on `public` - Moved destinations for `nodebb.min.js`, `acp.min.js`, `admin.css`, `stylesheet.css`, `templates`, and `sounds` to `build/public` - r.js modules previously routed through express are now symlinked into `public/build/src/modules` - minfiles no longer served from a memory cache - use config `views_dir` setting everywhere template directory is used - fix cache buster `v=v=` --- .eslintignore | 1 + app.js | 2 +- build.js | 1 + public/src/ajaxify.js | 2 +- public/src/app.js | 4 +- public/src/client/account/header.js | 2 +- public/src/modules/translator.js | 4 +- public/src/require-config.js | 2 +- public/src/widgets.js | 2 +- src/admin/search.js | 5 +- src/controllers/admin/settings.js | 3 +- src/controllers/admin/uploads.js | 2 +- src/coverPhoto.js | 2 +- src/meta/css.js | 24 +------- src/meta/js.js | 84 +++++++++------------------- src/meta/sounds.js | 4 +- src/meta/themes.js | 2 +- src/middleware/admin.js | 2 +- src/middleware/header.js | 2 +- src/routes/index.js | 38 +++++++++++-- src/routes/meta.js | 30 ---------- src/views/admin/header.tpl | 26 ++++----- src/views/admin/settings/group.tpl | 2 +- src/views/admin/settings/uploads.tpl | 2 +- src/webserver.js | 4 -- src/widgets/admin.js | 3 +- test/mocks/databasemock.js | 2 +- 27 files changed, 100 insertions(+), 157 deletions(-) diff --git a/.eslintignore b/.eslintignore index 0799652254..250640f954 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,3 +18,4 @@ logs/ *.ipr *.iws /coverage +/build diff --git a/app.js b/app.js index b6d7d07829..55cc0dbecf 100644 --- a/app.js +++ b/app.js @@ -99,7 +99,7 @@ function loadConfig(callback) { nconf.defaults({ base_dir: __dirname, themes_path: path.join(__dirname, 'node_modules'), - views_dir: path.join(__dirname, 'public/templates'), + views_dir: path.join(__dirname, 'build/public/templates'), version: pkg.version }); diff --git a/build.js b/build.js index a0250dfb37..32359e14f8 100644 --- a/build.js +++ b/build.js @@ -57,6 +57,7 @@ exports.buildTargets = function (targets, callback) { winston.info('[build] Building javascript'); var startTime = Date.now(); async.series([ + meta.js.linkModules, async.apply(meta.js.minify, 'nodebb.min.js'), async.apply(meta.js.minify, 'acp.min.js') ], step.bind(this, startTime, 'js', next)); diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 2e895f380b..7eb46343e5 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -338,7 +338,7 @@ $(document).ready(function () { callback(templates.cache[template]); } else { $.ajax({ - url: RELATIVE_PATH + '/templates/' + template + '.tpl' + (config['cache-buster'] ? '?v=' + config['cache-buster'] : ''), + url: config.relative_path + '/assets/templates/' + template + '.tpl' + '?' + config['cache-buster'], type: 'GET', success: function (data) { callback(data.toString()); diff --git a/public/src/app.js b/public/src/app.js index fe12a7adfc..00d5e7c017 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -558,7 +558,7 @@ app.cacheBuster = null; var scriptEl = document.createElement('script'); scriptEl.type = 'text/javascript'; - scriptEl.src = config.relative_path + '/vendor/jquery/js/jquery-ui.js' + (app.cacheBuster ? '?v=' + app.cacheBuster : ''); + scriptEl.src = config.relative_path + '/vendor/jquery/js/jquery-ui.js' + '?' + config['cache-buster']; scriptEl.onload = callback; document.head.appendChild(scriptEl); }; @@ -625,7 +625,7 @@ app.cacheBuster = null; app.loadProgressiveStylesheet = function () { var linkEl = document.createElement('link'); linkEl.rel = 'stylesheet'; - linkEl.href = config.relative_path + '/js-enabled.css'; + linkEl.href = config.relative_path + '/assets/js-enabled.css'; document.head.appendChild(linkEl); }; diff --git a/public/src/client/account/header.js b/public/src/client/account/header.js index e99b7ee0a8..d0f84ade3a 100644 --- a/public/src/client/account/header.js +++ b/public/src/client/account/header.js @@ -84,7 +84,7 @@ define('forum/account/header', [ params: {uid: ajaxify.data.uid }, accept: '.png,.jpg,.bmp' }, function (imageUrlOnServer) { - components.get('account/cover').css('background-image', 'url(' + imageUrlOnServer + '?v=' + Date.now() + ')'); + components.get('account/cover').css('background-image', 'url(' + imageUrlOnServer + '?' + config['cache-buster'] + ')'); }); }, removeCover diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index eac467f413..ff2aa53bb0 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -513,12 +513,12 @@ break; } - jQuery.getScript(config.relative_path + '/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').done(function () { + jQuery.getScript(config.relative_path + '/assets/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').done(function () { jQuery('.timeago').timeago(); adaptor.timeagoShort = assign({}, jQuery.timeago.settings.strings); // Retrieve the shorthand timeago values as well - jQuery.getScript(config.relative_path + '/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '-short.js').done(function () { + jQuery.getScript(config.relative_path + '/assets/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '-short.js').done(function () { // Switch back to long-form adaptor.toggleTimeagoShorthand(); }); diff --git a/public/src/require-config.js b/public/src/require-config.js index 8618685052..0e021f6be0 100644 --- a/public/src/require-config.js +++ b/public/src/require-config.js @@ -1,5 +1,5 @@ require.config({ - baseUrl: config.relative_path + "/src/modules", + baseUrl: config.relative_path + '/assets/src/modules', waitSeconds: 7, urlArgs: config['cache-buster'], paths: { diff --git a/public/src/widgets.js b/public/src/widgets.js index 46023fad15..377ccb2c53 100644 --- a/public/src/widgets.js +++ b/public/src/widgets.js @@ -29,7 +29,7 @@ } }); - $.get(config.relative_path + '/api/widgets/render' + (config['cache-buster'] ? '?v=' + config['cache-buster'] : ''), { + $.get(config.relative_path + '/api/widgets/render' + '?' + config['cache-buster'], { locations: widgetLocations, template: template + '.tpl', url: url, diff --git a/src/admin/search.js b/src/admin/search.js index 860c527e6b..4c53815e48 100644 --- a/src/admin/search.js +++ b/src/admin/search.js @@ -4,6 +4,7 @@ var fs = require('fs'); var path = require('path'); var async = require('async'); var sanitizeHTML = require('sanitize-html'); +var nconf = require('nconf'); var utils = require('../../public/src/utils'); var Translator = require('../../public/src/modules/translator').Translator; @@ -23,7 +24,7 @@ function filterDirectories(directories) { } function getAdminNamespaces(callback) { - utils.walk(path.resolve(__dirname, '../../public/templates/admin'), function (err, directories) { + utils.walk(path.resolve(nconf.get('views_dir'), 'admin'), function (err, directories) { if (err) { return callback(err); } @@ -60,7 +61,7 @@ var fallbackCacheInProgress = {}; var fallbackCache = {}; function initFallback(namespace, callback) { - fs.readFile(path.resolve(__dirname, '../../public/templates/', namespace + '.tpl'), function (err, file) { + fs.readFile(path.resolve(nconf.get('views_dir'), namespace + '.tpl'), function (err, file) { if (err) { return callback(err); } diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js index 639267f5f5..0d1f509631 100644 --- a/src/controllers/admin/settings.js +++ b/src/controllers/admin/settings.js @@ -2,6 +2,7 @@ var async = require('async'); +var nconf = require('nconf'); var meta = require('../../meta'); var settingsController = module.exports; @@ -25,7 +26,7 @@ function renderEmail(req, res, next) { var path = require('path'); var utils = require('../../../public/src/utils'); - var emailsPath = path.join(__dirname, '../../../public/templates/emails'); + var emailsPath = path.join(nconf.get('views_dir'), 'emails'); async.waterfall([ function (next) { diff --git a/src/controllers/admin/uploads.js b/src/controllers/admin/uploads.js index d1664cb8f1..2b1a60e281 100644 --- a/src/controllers/admin/uploads.js +++ b/src/controllers/admin/uploads.js @@ -105,7 +105,7 @@ uploadsController.uploadSound = function (req, res, next) { return next(err); } - var soundsPath = path.join(__dirname, '../../../public/sounds'), + var soundsPath = path.join(__dirname, '../../../build/public/sounds'), filePath = path.join(__dirname, '../../../public/uploads/sounds', uploadedFile.name); if (process.platform === 'win32') { diff --git a/src/coverPhoto.js b/src/coverPhoto.js index 699e4ee374..9380b347f4 100644 --- a/src/coverPhoto.js +++ b/src/coverPhoto.js @@ -26,7 +26,7 @@ function getCover(type, id) { return covers[id]; } - return nconf.get('relative_path') + '/images/cover-default.png'; + return nconf.get('relative_path') + '/assets/images/cover-default.png'; } module.exports = coverPhoto; \ No newline at end of file diff --git a/src/meta/css.js b/src/meta/css.js index 0d63e09d6d..f72ef6004d 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -86,15 +86,6 @@ module.exports = function (Meta) { }); }; - Meta.css.getFromFile = function (callback) { - async.series([ - async.apply(Meta.css.loadFile, path.join(__dirname, '../../public/stylesheet.css'), 'cache'), - async.apply(Meta.css.loadFile, path.join(__dirname, '../../public/admin.css'), 'acpCache') - ], function (err) { - callback(err); - }); - }; - function getStyleSource(files, prefix, extension, callback) { var pluginDirectories = [], source = ''; @@ -127,7 +118,7 @@ module.exports = function (Meta) { Meta.css.commitToFile = function (filename, callback) { var file = (filename === 'acpCache' ? 'admin' : 'stylesheet') + '.css'; - fs.writeFile(path.join(__dirname, '../../public/' + file), Meta.css[filename], function (err) { + fs.writeFile(path.join(__dirname, '../../build/public/' + file), Meta.css[filename], function (err) { if (!err) { winston.verbose('[meta/css] ' + file + ' committed to disk.'); } else { @@ -139,19 +130,6 @@ module.exports = function (Meta) { }); }; - Meta.css.loadFile = function (filePath, filename, callback) { - winston.verbose('[meta/css] Reading stylesheet ' + filePath.split('/').pop() + ' from file'); - - fs.readFile(filePath, function (err, file) { - if (err) { - return callback(err); - } - - Meta.css[filename] = file; - callback(); - }); - }; - function minify(source, paths, destination, callback) { callback = callback || function () {}; less.render(source, { diff --git a/src/meta/js.js b/src/meta/js.js index 7f39235993..8c3794043f 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -6,6 +6,7 @@ var path = require('path'); var async = require('async'); var nconf = require('nconf'); var fs = require('fs'); +var mkdirp = require('mkdirp'); var plugins = require('../plugins'); var utils = require('../../public/src/utils'); @@ -85,30 +86,34 @@ module.exports = function (Meta) { } } }; - - Meta.js.bridgeModules = function (app, callback) { - // Add routes for AMD-type modules to serve those files - function addRoute(relPath) { - var relativePath = nconf.get('relative_path'); - - app.get(relativePath + '/src/modules/' + relPath, function (req, res) { - return res.sendFile(path.join(__dirname, '../../', Meta.js.scripts.modules[relPath]), { - maxAge: app.enabled('cache') ? 5184000000 : 0 - }); - }); + + Meta.js.linkModules = function (callback) { + function link(filePath, destPath, cb) { + if (process.platform === 'win32') { + fs.link(filePath, destPath, cb); + } else { + fs.symlink(filePath, destPath, 'file', cb); + } } - var numBridged = 0; - - for(var relPath in Meta.js.scripts.modules) { - if (Meta.js.scripts.modules.hasOwnProperty(relPath)) { - addRoute(relPath); - ++numBridged; + plugins.reload(function (err) { + if (err) { + return callback(err); } - } + + async.each(Object.keys(Meta.js.scripts.modules), function (relPath, next) { + var filePath = path.join(__dirname, '../../', Meta.js.scripts.modules[relPath]); + var destPath = path.join(__dirname, '../../build/public/src/modules', relPath); + + mkdirp(path.dirname(destPath), function (err) { + if (err) { + return next(err); + } - winston.verbose('[meta/js] ' + numBridged + ' of ' + Object.keys(Meta.js.scripts.modules).length + ' modules bridged'); - callback(); + link(filePath, destPath, next); + }); + }, callback); + }); }; Meta.js.minify = function (target, callback) { @@ -202,48 +207,11 @@ module.exports = function (Meta) { }; Meta.js.commitToFile = function (target, callback) { - fs.writeFile(path.join(__dirname, '../../public/' + target), Meta.js.target[target].cache, function (err) { + fs.writeFile(path.join(__dirname, '../../build/public/' + target), Meta.js.target[target].cache, function (err) { callback(err); }); }; - Meta.js.getFromFile = function (target, callback) { - function readFile(filePath, next) { - fs.readFile(filePath, function (err, contents) { - if (err) { - if (err.code === 'ENOENT') { - if (!filePath.endsWith('.map')) { - winston.warn('[meta/js] ' + filePath + ' not found on disk, did you run ./nodebb build?'); - } - return next(null, ''); - } - } - next(err, contents); - }); - } - - var scriptPath = path.join(nconf.get('base_dir'), 'public/' + target); - var mapPath = path.join(nconf.get('base_dir'), 'public/' + target + '.map'); - - async.parallel({ - script: function (next) { - readFile(scriptPath, next); - }, - map: function (next) { - readFile(mapPath, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } - Meta.js.target[target] = { - cache: results.script, - map: results.map - }; - callback(); - }); - }; - function setupDebugging() { /** * Check if the parent process is running with the debug option --debug (or --debug-brk) diff --git a/src/meta/sounds.js b/src/meta/sounds.js index 6068f16f5f..6acbd77a1f 100644 --- a/src/meta/sounds.js +++ b/src/meta/sounds.js @@ -28,7 +28,7 @@ module.exports = function (Meta) { Meta.sounds.getFiles = function (callback) { async.waterfall([ function (next) { - fs.readdir(path.join(__dirname, '../../public/sounds'), next); + fs.readdir(path.join(__dirname, '../../build/public/sounds'), next); }, function (sounds, next) { fs.readdir(path.join(__dirname, '../../public/uploads/sounds'), function (err, uploaded) { @@ -88,7 +88,7 @@ module.exports = function (Meta) { }; function setupSounds(callback) { - var soundsPath = path.join(__dirname, '../../public/sounds'); + var soundsPath = path.join(__dirname, '../../build/public/sounds'); async.waterfall([ function (next) { diff --git a/src/meta/themes.js b/src/meta/themes.js index be48d1e70d..e19dcdbf4c 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -48,7 +48,7 @@ module.exports = function (Meta) { if (configObj.screenshot) { configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id; } else { - configObj.screenshot_url = nconf.get('relative_path') + '/images/themes/default.png'; + configObj.screenshot_url = nconf.get('relative_path') + '/assets/images/themes/default.png'; } next(null, configObj); } catch (err) { diff --git a/src/middleware/admin.js b/src/middleware/admin.js index 3240eaf0af..9d4b43bf25 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -101,7 +101,7 @@ module.exports = function (middleware) { plugins: results.custom_header.plugins, authentication: results.custom_header.authentication, scripts: results.scripts, - 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', + 'cache-buster': meta.config['cache-buster'] || '', env: process.env.NODE_ENV ? true : false, title: (acpPath || 'Dashboard') + ' | NodeBB Admin Control Panel', bodyClass: data.bodyClass diff --git a/src/middleware/header.js b/src/middleware/header.js index c1b4175b5b..5e78416a0a 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -46,7 +46,7 @@ module.exports = function (middleware) { bootswatchCSS: meta.config['theme:src'], title: meta.config.title || '', description: meta.config.description || '', - 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', + 'cache-buster': meta.config['cache-buster'] || '', 'brand:logo': meta.config['brand:logo'] || '', 'brand:logo:url': meta.config['brand:logo:url'] || '', 'brand:logo:alt': meta.config['brand:logo:alt'] || '', diff --git a/src/routes/index.js b/src/routes/index.js index 158774b624..e1f95891cf 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -145,21 +145,47 @@ module.exports = function (app, middleware, hotswapIds) { } app.use(middleware.privateUploads); - app.use(relativePath + '/assets', express.static(path.join(__dirname, '../../', 'build/public'), { + + app.use(relativePath + '/assets', express.static(path.join(__dirname, '../../build/public'), { + maxAge: app.enabled('cache') ? 5184000000 : 0 + })); + app.use(relativePath + '/assets', express.static(path.join(__dirname, '../../public'), { maxAge: app.enabled('cache') ? 5184000000 : 0 })); + // DEPRECATED + var deprecatedPaths = [ + '/nodebb.min.js', + '/acp.min.js', + '/stylesheet.css', + '/js-enabled.css', + '/admin.css', + '/logo.png', + '/favicon.ico', + '/vendor/', + '/uploads/', + '/templates/', + '/src/', + '/images/', + // '/sounds/', + ]; + app.use(relativePath, function (req, res, next) { + if (deprecatedPaths.some(function (path) { return req.path.startsWith(path); })) { + winston.warn('[deprecated] Accessing `' + req.path.slice(1) + '` from `/` is deprecated. ' + + 'Use `/assets' + req.path + '` to access this file.'); + res.redirect(relativePath + '/assets' + req.path + '?' + meta.config['cache-buster']); + } else { + next(); + } + }); // DEPRECATED app.use(relativePath + '/api/language', function (req, res) { winston.warn('[deprecated] Accessing language files from `/api/language` is deprecated. ' + - 'Use `/assets/language/[langCode]/[namespace].json` for prefetch paths.'); + 'Use `/assets/language' + req.path + '.json` for prefetch paths.'); res.redirect(relativePath + '/assets/language' + req.path + '.json?' + meta.config['cache-buster']); }); - app.use(relativePath, express.static(path.join(__dirname, '../../', 'public'), { - maxAge: app.enabled('cache') ? 5184000000 : 0 - })); - app.use(relativePath + '/vendor/jquery/timeago/locales', middleware.processTimeagoLocales); + app.use(relativePath + '/assets/vendor/jquery/timeago/locales', middleware.processTimeagoLocales); app.use(controllers.handle404); app.use(controllers.handleURIErrors); app.use(controllers.handleErrors); diff --git a/src/routes/meta.js b/src/routes/meta.js index c62465c8d0..af4e89d897 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -5,31 +5,6 @@ var nconf = require('nconf'); var meta = require('../meta'); - -function sendMinifiedJS(req, res) { - var target = path.basename(req.path); - var cache = meta.js.target[target] ? meta.js.target[target].cache : ''; - res.type('text/javascript').send(cache); -} - -// The portions of code involving the source map are commented out as they're broken in UglifyJS2 -// Follow along here: https://github.com/mishoo/UglifyJS2/issues/700 -// function sendJSSourceMap(req, res) { -// if (meta.js.hasOwnProperty('map')) { -// res.type('application/json').send(meta.js.map); -// } else { -// res.redirect(404); -// } -// }; - -function sendStylesheet(req, res) { - res.type('text/css').status(200).send(meta.css.cache); -} - -function sendACPStylesheet(req, res) { - res.type('text/css').status(200).send(meta.css.acpCache); -} - function sendSoundFile(req, res, next) { var resolved = meta.sounds._filePathHash[path.basename(req.path)]; @@ -41,11 +16,6 @@ function sendSoundFile(req, res, next) { } module.exports = function (app, middleware, controllers) { - app.get('/stylesheet.css', middleware.addExpiresHeaders, sendStylesheet); - app.get('/admin.css', middleware.addExpiresHeaders, sendACPStylesheet); - app.get('/nodebb.min.js', middleware.addExpiresHeaders, sendMinifiedJS); - app.get('/acp.min.js', middleware.addExpiresHeaders, sendMinifiedJS); - // app.get('/nodebb.min.js.map', middleware.addExpiresHeaders, sendJSSourceMap); app.get('/sitemap.xml', controllers.sitemap.render); app.get('/sitemap/pages.xml', controllers.sitemap.getPages); app.get('/sitemap/categories.xml', controllers.sitemap.getCategories); diff --git a/src/views/admin/header.tpl b/src/views/admin/header.tpl index e6e92490f9..23ce1e2c02 100644 --- a/src/views/admin/header.tpl +++ b/src/views/admin/header.tpl @@ -4,8 +4,8 @@ {title} - - + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index 56a8b2c18e..1c0b660361 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -43,7 +43,7 @@

[[admin/settings/group:default-cover-help]]

-
+
diff --git a/src/views/admin/settings/uploads.tpl b/src/views/admin/settings/uploads.tpl index 2e79da9a2b..6c9b59db80 100644 --- a/src/views/admin/settings/uploads.tpl +++ b/src/views/admin/settings/uploads.tpl @@ -131,7 +131,7 @@

[[admin/settings/uploads:default-covers-help]]

- + diff --git a/src/webserver.js b/src/webserver.js index fec42974c6..2e7afdb228 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -88,7 +88,6 @@ function initializeNodeBB(callback) { plugins.init(app, middleware, next); }, async.apply(plugins.fireHook, 'static:assets.prepare', {}), - async.apply(meta.js.bridgeModules, app), function (next) { plugins.fireHook('static:app.preload', { app: app, @@ -104,9 +103,6 @@ function initializeNodeBB(callback) { }, function (next) { async.series([ - async.apply(meta.js.getFromFile, 'nodebb.min.js'), - async.apply(meta.js.getFromFile, 'acp.min.js'), - async.apply(meta.css.getFromFile), async.apply(meta.sounds.init), async.apply(languages.init), async.apply(meta.blacklist.load) diff --git a/src/widgets/admin.js b/src/widgets/admin.js index fc380804c6..ecfd73b750 100644 --- a/src/widgets/admin.js +++ b/src/widgets/admin.js @@ -3,6 +3,7 @@ var fs = require('fs'); var path = require('path'); var async = require('async'); +var nconf = require('nconf'); var plugins = require('../plugins'); var admin = {}; @@ -25,7 +26,7 @@ admin.get = function (callback) { plugins.fireHook('filter:widgets.getWidgets', [], next); }, adminTemplate: function (next) { - fs.readFile(path.resolve(__dirname, '../../public/templates/admin/partials/widget-settings.tpl'), 'utf8', next); + fs.readFile(path.resolve(nconf.get('views_dir'), 'admin/partials/widget-settings.tpl'), 'utf8', next); } }, function (err, widgetData) { if (err) { diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 44de8c7122..182d9fea12 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -20,7 +20,7 @@ base_dir: path.join(__dirname,'../..'), themes_path: path.join(__dirname, '../../node_modules'), upload_url: path.join(path.sep, '../../uploads', path.sep), - views_dir: path.join(__dirname, '../../public/templates'), + views_dir: path.join(__dirname, '../../build/public/templates'), relative_path: '' });