diff --git a/.eslintrc.js b/.eslintrc.js index e36c70b52..6e862d783 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,4 @@ module.exports = { - extends: ['scratch', 'scratch/node'], + extends: ['scratch', 'scratch/node', 'scratch/es6'], plugins: ['json'] }; diff --git a/bin/announce.js b/bin/announce.js index f39d6f4b0..c070b7e0d 100644 --- a/bin/announce.js +++ b/bin/announce.js @@ -2,15 +2,15 @@ const https = require('https'); -let environment = process.env.SCRATCH_ENV || 'unknown environment'; +const environment = process.env.SCRATCH_ENV || 'unknown environment'; -let branch = process.env.CIRCLE_BRANCH || 'unknown branch'; +const branch = process.env.CIRCLE_BRANCH || 'unknown branch'; -let urlEng = process.env.SLACK_WEBHOOK_ENGINEERING; -let urlMod = process.env.SLACK_WEBHOOK_MODS; -let urlNotifications = process.env.SLACK_WEBHOOK_CIRCLECI_NOTIFICATIONS; +const urlEng = process.env.SLACK_WEBHOOK_ENGINEERING; +const urlMod = process.env.SLACK_WEBHOOK_MODS; +const urlNotifications = process.env.SLACK_WEBHOOK_CIRCLECI_NOTIFICATIONS; -let announcement = {text: `scratch-www has deployed branch ${branch} to ${environment}.`}; +const announcement = {text: `scratch-www has deployed branch ${branch} to ${environment}.`}; const options = { method: 'POST', @@ -20,11 +20,11 @@ const options = { }; const postMessage = (url, message, channelName) => { - let data = JSON.stringify(message); + const data = JSON.stringify(message); const req = https.request(url, options, res => { console.log(`statusCode: ${res.statusCode}`); // eslint-disable-line no-console if (res.statusCode === 200) { - process.stdout.write(`announced to ${channelName}\n` + JSON.stringify(message) + '\n'); + process.stdout.write(`announced to ${channelName}\n${JSON.stringify(message)}\n`); } else { process.stdout.write(`FAILED to announce to slack`); } diff --git a/bin/configure-fastly.js b/bin/configure-fastly.js index 6e0ad1984..3fec0a330 100644 --- a/bin/configure-fastly.js +++ b/bin/configure-fastly.js @@ -1,16 +1,16 @@ -var async = require('async'); -var defaults = require('lodash.defaults'); -var fastlyConfig = require('./lib/fastly-config-methods'); +const async = require('async'); +const defaults = require('lodash.defaults'); +const fastlyConfig = require('./lib/fastly-config-methods'); const languages = require('scratch-l10n').default; -var routeJson = require('../src/routes.json'); +const routeJson = require('../src/routes.json'); const FASTLY_SERVICE_ID = process.env.FASTLY_SERVICE_ID || ''; const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || ''; -var fastly = require('./lib/fastly-extended')(process.env.FASTLY_API_KEY, FASTLY_SERVICE_ID); +const fastly = require('./lib/fastly-extended')(process.env.FASTLY_API_KEY, FASTLY_SERVICE_ID); -var extraAppRoutes = [ +const extraAppRoutes = [ // Homepage with querystring. // TODO: Should this be added for every route? '/\\?', @@ -18,18 +18,18 @@ var extraAppRoutes = [ '/[^/]*.html$' ]; -var routes = routeJson.map(function (route) { - return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route); -}); +const routes = routeJson.map( + route => defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route) +); async.auto({ version: function (cb) { - fastly.getLatestActiveVersion(function (err, response) { + fastly.getLatestActiveVersion((err, response) => { if (err) return cb(err); // Validate latest version before continuing if (response.active || response.locked) { - fastly.cloneVersion(response.number, function (e, resp) { - if (e) return cb('Failed to clone latest version: ' + e); + fastly.cloneVersion(response.number, (e, resp) => { + if (e) return cb(`Failed to clone latest version: ${e}`); cb(null, resp.number); }); } else { @@ -40,40 +40,40 @@ async.auto({ recvCustomVCL: ['version', function (results, cb) { // For all the routes in routes.json, construct a varnish-style regex that matches // on any of those route conditions. - var notPassStatement = fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname); + const notPassStatement = fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname); // For a non-pass condition, point backend at s3 - var recvCondition = '' + - 'if (' + notPassStatement + ') {\n' + - ' set req.backend = F_s3;\n' + - ' set req.http.host = "' + S3_BUCKET_NAME + '";\n' + - '} else {\n' + - ' if (!req.http.Fastly-FF) {\n' + - ' if (req.http.X-Forwarded-For) {\n' + - ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;\n' + - ' } else {\n' + - ' set req.http.Fastly-Temp-XFF = client.ip;\n' + - ' }\n' + - ' } else {\n' + - ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;\n' + - ' }\n' + - ' set req.grace = 60s;\n' + - ' if (req.http.Cookie:scratchlanguage) {\n' + - ' set req.http.Accept-Language = req.http.Cookie:scratchlanguage;\n' + - ' } else {\n' + - ' set req.http.Accept-Language = accept.language_lookup("' + - Object.keys(languages).join(':') + '", ' + - '"en", ' + - 'std.tolower(req.http.Accept-Language)' + - ');\n' + - ' }\n' + - ' if (req.url ~ "^(/projects/|/fragment/account-nav.json|/session/)" && ' + - '!req.http.Cookie:scratchsessionsid) {\n' + - ' set req.http.Cookie = "scratchlanguage=" req.http.Cookie:scratchlanguage;\n' + - ' } else {\n' + - ' return(pass);\n' + - ' }\n' + - '}\n'; + const recvCondition = `${'' + + 'if ('}${notPassStatement}) {\n` + + ` set req.backend = F_s3;\n` + + ` set req.http.host = "${S3_BUCKET_NAME}";\n` + + `} else {\n` + + ` if (!req.http.Fastly-FF) {\n` + + ` if (req.http.X-Forwarded-For) {\n` + + ` set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;\n` + + ` } else {\n` + + ` set req.http.Fastly-Temp-XFF = client.ip;\n` + + ` }\n` + + ` } else {\n` + + ` set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;\n` + + ` }\n` + + ` set req.grace = 60s;\n` + + ` if (req.http.Cookie:scratchlanguage) {\n` + + ` set req.http.Accept-Language = req.http.Cookie:scratchlanguage;\n` + + ` } else {\n` + + ` set req.http.Accept-Language = accept.language_lookup("${ + Object.keys(languages).join(':')}", ` + + `"en", ` + + `std.tolower(req.http.Accept-Language)` + + `);\n` + + ` }\n` + + ` if (req.url ~ "^(/projects/|/fragment/account-nav.json|/session/)" && ` + + `!req.http.Cookie:scratchsessionsid) {\n` + + ` set req.http.Cookie = "scratchlanguage=" req.http.Cookie:scratchlanguage;\n` + + ` } else {\n` + + ` return(pass);\n` + + ` }\n` + + `}\n`; fastly.setCustomVCL( @@ -84,48 +84,48 @@ async.auto({ ); }], fetchCustomVCL: ['version', function (results, cb) { - var passStatement = fastlyConfig.negateConditionStatement( + const passStatement = fastlyConfig.negateConditionStatement( fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname) ); - var ttlCondition = fastlyConfig.setResponseTTL(passStatement); + const ttlCondition = fastlyConfig.setResponseTTL(passStatement); fastly.setCustomVCL(results.version, 'fetch-condition', ttlCondition, cb); }], appRouteRequestConditions: ['version', function (results, cb) { - var conditions = {}; - async.forEachOf(routes, function (route, id, cb2) { - var condition = { + const conditions = {}; + async.forEachOf(routes, (route, id, cb2) => { + const condition = { name: fastlyConfig.getConditionNameForRoute(route, 'request'), - statement: 'req.url.path ~ "' + route.pattern + '"', + statement: `req.url.path ~ "${route.pattern}"`, type: 'REQUEST', // Priority needs to be > 1 to not interact with http->https redirect priority: 10 + id }; - fastly.setCondition(results.version, condition, function (err, response) { + fastly.setCondition(results.version, condition, (err, response) => { if (err) return cb2(err); conditions[id] = response; cb2(null, response); }); - }, function (err) { + }, err => { if (err) return cb(err); cb(null, conditions); }); }], appRouteHeaders: ['version', 'appRouteRequestConditions', function (results, cb) { - var headers = {}; - async.forEachOf(routes, function (route, id, cb2) { + const headers = {}; + async.forEachOf(routes, (route, id, cb2) => { if (route.redirect) { async.auto({ responseCondition: function (cb3) { - var condition = { + const condition = { name: fastlyConfig.getConditionNameForRoute(route, 'response'), - statement: 'req.url.path ~ "' + route.pattern + '"', + statement: `req.url.path ~ "${route.pattern}"`, type: 'RESPONSE', priority: id }; fastly.setCondition(results.version, condition, cb3); }, responseObject: function (cb3) { - var responseObject = { + const responseObject = { name: fastlyConfig.getResponseNameForRoute(route), status: 301, response: 'Moved Permanently', @@ -134,40 +134,40 @@ async.auto({ fastly.setResponseObject(results.version, responseObject, cb3); }, redirectHeader: ['responseCondition', function (redirectResults, cb3) { - var header = { + const header = { name: fastlyConfig.getHeaderNameForRoute(route), action: 'set', ignore_if_set: 0, type: 'RESPONSE', dst: 'http.Location', - src: '"' + route.redirect + '"', + src: `"${route.redirect}"`, response_condition: redirectResults.responseCondition.name }; fastly.setFastlyHeader(results.version, header, cb3); }] - }, function (err, redirectResults) { + }, (err, redirectResults) => { if (err) return cb2(err); headers[id] = redirectResults.redirectHeader; cb2(null, redirectResults); }); } else { - var header = { + const header = { name: fastlyConfig.getHeaderNameForRoute(route, 'request'), action: 'set', ignore_if_set: 0, type: 'REQUEST', dst: 'url', - src: '"/' + route.name + '.html"', + src: `"/${route.name}.html"`, request_condition: results.appRouteRequestConditions[id].name, priority: 10 }; - fastly.setFastlyHeader(results.version, header, function (err, response) { + fastly.setFastlyHeader(results.version, header, (err, response) => { if (err) return cb2(err); headers[id] = response; cb2(null, response); }); } - }, function (err) { + }, err => { if (err) return cb(err); cb(null, headers); }); @@ -175,7 +175,7 @@ async.auto({ tipbarRedirectHeaders: ['version', function (results, cb) { async.auto({ requestCondition: function (cb2) { - var condition = { + const condition = { name: 'routes/?tip_bar= (request)', statement: 'req.url ~ "\\?tip_bar="', type: 'REQUEST', @@ -184,7 +184,7 @@ async.auto({ fastly.setCondition(results.version, condition, cb2); }, responseCondition: function (cb2) { - var condition = { + const condition = { name: 'routes/?tip_bar= (response)', statement: 'req.url ~ "\\?tip_bar="', type: 'RESPONSE', @@ -193,7 +193,7 @@ async.auto({ fastly.setCondition(results.version, condition, cb2); }, responseObject: ['requestCondition', function (redirectResults, cb2) { - var responseObject = { + const responseObject = { name: 'redirects/?tip_bar=', status: 301, response: 'Moved Permanently', @@ -202,7 +202,7 @@ async.auto({ fastly.setResponseObject(results.version, responseObject, cb2); }], redirectHeader: ['responseCondition', function (redirectResults, cb2) { - var header = { + const header = { name: 'redirects/?tip_bar=', action: 'set', ignore_if_set: 0, @@ -213,7 +213,7 @@ async.auto({ }; fastly.setFastlyHeader(results.version, header, cb2); }] - }, function (err, redirectResults) { + }, (err, redirectResults) => { if (err) return cb(err); cb(null, redirectResults); }); @@ -221,7 +221,7 @@ async.auto({ embedRedirectHeaders: ['version', function (results, cb) { async.auto({ requestCondition: function (cb2) { - var condition = { + const condition = { name: 'routes/projects/embed (request)', statement: 'req.url.path ~ "^/projects/embed/(\\d+)"', type: 'REQUEST', @@ -230,7 +230,7 @@ async.auto({ fastly.setCondition(results.version, condition, cb2); }, responseCondition: function (cb2) { - var condition = { + const condition = { name: 'routes/projects/embed (response)', statement: 'req.url.path ~ "^/projects/embed/(\\d+)"', type: 'RESPONSE', @@ -239,7 +239,7 @@ async.auto({ fastly.setCondition(results.version, condition, cb2); }, responseObject: ['requestCondition', function (redirectResults, cb2) { - var responseObject = { + const responseObject = { name: 'redirects/projects/embed', status: 301, response: 'Moved Permanently', @@ -248,7 +248,7 @@ async.auto({ fastly.setResponseObject(results.version, responseObject, cb2); }], redirectHeader: ['responseCondition', function (redirectResults, cb2) { - var header = { + const header = { name: 'redirects/projects/embed', action: 'set', ignore_if_set: 0, @@ -259,19 +259,19 @@ async.auto({ }; fastly.setFastlyHeader(results.version, header, cb2); }] - }, function (err, redirectResults) { + }, (err, redirectResults) => { if (err) return cb(err); cb(null, redirectResults); }); }] -}, function (err, results) { +}, (err, results) => { if (err) throw new Error(err); if (process.env.FASTLY_ACTIVATE_CHANGES) { - fastly.activateVersion(results.version, function (e, resp) { + fastly.activateVersion(results.version, (e, resp) => { if (e) throw new Error(e); - process.stdout.write('Successfully configured and activated version ' + resp.number + '\n'); + process.stdout.write(`Successfully configured and activated version ${resp.number}\n`); // purge static-assets using surrogate key - fastly.purgeKey(FASTLY_SERVICE_ID, 'static-assets', function (error) { + fastly.purgeKey(FASTLY_SERVICE_ID, 'static-assets', error => { if (error) throw new Error(error); process.stdout.write('Purged static assets.\n'); }); diff --git a/bin/lib/fastly-config-methods.js b/bin/lib/fastly-config-methods.js index d6a8c973d..7b86c302d 100644 --- a/bin/lib/fastly-config-methods.js +++ b/bin/lib/fastly-config-methods.js @@ -1,19 +1,19 @@ -var glob = require('glob'); -var path = require('path'); +const glob = require('glob'); +const path = require('path'); -var FastlyConfigMethods = { +const FastlyConfigMethods = { /* * Given the relative path to the static directory, return an array of * patterns matching the files and directories there. */ getStaticPaths: function (rootDir, pathToStatic) { - var staticPaths = glob.sync(path.resolve(rootDir, pathToStatic)); - return staticPaths.filter(function (pathName) { + const staticPaths = glob.sync(path.resolve(rootDir, pathToStatic)); + return staticPaths.filter(pathName => // Exclude view html, resolve everything else in the build - return path.extname(pathName) !== '.html'; - }).map(function (pathName) { + path.extname(pathName) !== '.html' + ).map(pathName => { // Reduce absolute path to relative paths like '/js' - var base = path.dirname(path.resolve(rootDir, pathToStatic)); + const base = path.dirname(path.resolve(rootDir, pathToStatic)); return pathName.replace(base, '') + (path.extname(pathName) ? '' : '/'); }); }, @@ -23,8 +23,8 @@ var FastlyConfigMethods = { * the express route and a static view file associated with the route */ getViewPaths: function (routes) { - return routes.reduce(function (paths, route) { - var p = route.routeAlias || route.pattern; + return routes.reduce((paths, route) => { + const p = route.routeAlias || route.pattern; if (paths.indexOf(p) === -1) { paths.push(p); } @@ -48,16 +48,16 @@ var FastlyConfigMethods = { * string suitable for a Fastly condition */ pathsToCondition: function (paths) { - return 'req.url~"^(' + paths.reduce(function (conditionString, pattern) { - return conditionString + (conditionString ? '|' : '') + pattern; - }, '') + ')"'; + return `req.url~"^(${ + paths.reduce((conditionString, pattern) => conditionString + (conditionString ? '|' : '') + pattern, '') + })"`; }, /* * Helper method to NOT a condition statement */ negateConditionStatement: function (statement) { - return '!(' + statement + ')'; + return `!(${statement})`; }, /* @@ -65,23 +65,23 @@ var FastlyConfigMethods = { * fastly condition to match req.url */ getAppRouteCondition: function (pathToStatic, routes, additionalPaths, rootDir) { - var staticPaths = FastlyConfigMethods.getStaticPaths(rootDir, pathToStatic); - var viewPaths = FastlyConfigMethods.getViewPaths(routes); - var allPaths = [].concat(staticPaths, viewPaths, additionalPaths); + const staticPaths = FastlyConfigMethods.getStaticPaths(rootDir, pathToStatic); + const viewPaths = FastlyConfigMethods.getViewPaths(routes); + const allPaths = [].concat(staticPaths, viewPaths, additionalPaths); return FastlyConfigMethods.pathsToCondition(allPaths); }, getConditionNameForRoute: function (route, type) { - return 'routes/' + route.pattern + ' (' + type + ')'; + return `routes/${route.pattern} (${type})`; }, getHeaderNameForRoute: function (route) { - if (route.name) return 'rewrites/' + route.name; - if (route.redirect) return 'redirects/' + route.pattern; + if (route.name) return `rewrites/${route.name}`; + if (route.redirect) return `redirects/${route.pattern}`; }, getResponseNameForRoute: function (route) { - return 'redirects/' + route.pattern; + return `redirects/${route.pattern}`; }, /* @@ -91,19 +91,19 @@ var FastlyConfigMethods = { * @param {string} condition condition under which the response should be set */ setResponseTTL: function (condition) { - return '' + - 'if (' + condition + ') {\n' + - ' if (req.url ~ "^(/projects/|/fragment/account-nav.json|/session/)" && ' + - '!req.http.Cookie:scratchsessionsid) {\n' + - ' set beresp.http.Vary = "Accept-Encoding, Accept-Language";\n' + - ' unset beresp.http.set-cookie;\n' + - ' return(deliver);\n' + - ' } else {\n' + - ' set beresp.ttl = 0s;\n' + - ' set beresp.grace = 0s;\n' + - ' return(pass);\n' + - ' }\n' + - '}\n'; + return `${'' + + 'if ('}${condition}) {\n` + + ` if (req.url ~ "^(/projects/|/fragment/account-nav.json|/session/)" && ` + + `!req.http.Cookie:scratchsessionsid) {\n` + + ` set beresp.http.Vary = "Accept-Encoding, Accept-Language";\n` + + ` unset beresp.http.set-cookie;\n` + + ` return(deliver);\n` + + ` } else {\n` + + ` set beresp.ttl = 0s;\n` + + ` set beresp.grace = 0s;\n` + + ` return(pass);\n` + + ` }\n` + + `}\n`; } }; diff --git a/bin/lib/fastly-extended.js b/bin/lib/fastly-extended.js index ffac40acc..0ff1aacb2 100644 --- a/bin/lib/fastly-extended.js +++ b/bin/lib/fastly-extended.js @@ -1,4 +1,4 @@ -var Fastly = require('fastly'); +const Fastly = require('fastly'); /* * Fastly library extended to allow configuration for a particular service @@ -8,7 +8,7 @@ var Fastly = require('fastly'); * @param {string} Service id */ module.exports = function (apiKey, serviceId) { - var fastly = Fastly(apiKey); + const fastly = Fastly(apiKey); fastly.serviceId = serviceId; /* @@ -20,7 +20,7 @@ module.exports = function (apiKey, serviceId) { * @return {string} */ fastly.getFastlyAPIPrefix = function (servId, version) { - return '/service/' + encodeURIComponent(servId) + '/version/' + version; + return `/service/${encodeURIComponent(servId)}/version/${version}`; }; /* @@ -32,12 +32,12 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { return cb('Failed to get latest version. No serviceId configured'); } - var url = '/service/' + encodeURIComponent(this.serviceId) + '/version'; - this.request('GET', url, function (err, versions) { + const url = `/service/${encodeURIComponent(this.serviceId)}/version`; + this.request('GET', url, (err, versions) => { if (err) { - return cb('Failed to fetch versions: ' + err); + return cb(`Failed to fetch versions: ${err}`); } - var latestVersion = versions.reduce((latestActiveSoFar, cur) => { + const latestVersion = versions.reduce((latestActiveSoFar, cur) => { // if one of [latestActiveSoFar, cur] is active and the other isn't, // return whichever is active. If both are not active, return // latestActiveSoFar. @@ -62,24 +62,24 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { return cb('Failed to set condition. No serviceId configured'); } - var name = condition.name; - var putUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/condition/' + encodeURIComponent(name); - var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/condition'; - return this.request('PUT', putUrl, condition, function (err, response) { + const name = condition.name; + const putUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/condition/${encodeURIComponent(name)}`; + const postUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/condition`; + return this.request('PUT', putUrl, condition, (err, response) => { if (err && err.statusCode === 404) { - this.request('POST', postUrl, condition, function (e, resp) { + this.request('POST', postUrl, condition, (e, resp) => { if (e) { - return cb('Failed while inserting condition "' + condition.statement + '": ' + e); + return cb(`Failed while inserting condition "${condition.statement}": ${e}`); } return cb(null, resp); }); return; } if (err) { - return cb('Failed to update condition "' + condition.statement + '": ' + err); + return cb(`Failed to update condition "${condition.statement}": ${err}`); } return cb(null, response); - }.bind(this)); + }); }; /* @@ -94,24 +94,24 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { cb('Failed to set header. No serviceId configured'); } - var name = header.name; - var putUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/header/' + encodeURIComponent(name); - var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/header'; - return this.request('PUT', putUrl, header, function (err, response) { + const name = header.name; + const putUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/header/${encodeURIComponent(name)}`; + const postUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/header`; + return this.request('PUT', putUrl, header, (err, response) => { if (err && err.statusCode === 404) { - this.request('POST', postUrl, header, function (e, resp) { + this.request('POST', postUrl, header, (e, resp) => { if (e) { - return cb('Failed to insert header: ' + e); + return cb(`Failed to insert header: ${e}`); } return cb(null, resp); }); return; } if (err) { - return cb('Failed to update header: ' + err); + return cb(`Failed to update header: ${err}`); } return cb(null, response); - }.bind(this)); + }); }; /* @@ -126,24 +126,25 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { cb('Failed to set response object. No serviceId configured'); } - var name = responseObj.name; - var putUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/response_object/' + encodeURIComponent(name); - var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/response_object'; - return this.request('PUT', putUrl, responseObj, function (err, response) { + const name = responseObj.name; + const putUrl = + `${this.getFastlyAPIPrefix(this.serviceId, version)}/response_object/${encodeURIComponent(name)}`; + const postUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/response_object`; + return this.request('PUT', putUrl, responseObj, (err, response) => { if (err && err.statusCode === 404) { - this.request('POST', postUrl, responseObj, function (e, resp) { + this.request('POST', postUrl, responseObj, (e, resp) => { if (e) { - return cb('Failed to insert response object: ' + e); + return cb(`Failed to insert response object: ${e}`); } return cb(null, resp); }); return; } if (err) { - return cb('Failed to update response object: ' + err); + return cb(`Failed to update response object: ${err}`); } return cb(null, response); - }.bind(this)); + }); }; /* @@ -154,7 +155,7 @@ module.exports = function (apiKey, serviceId) { */ fastly.cloneVersion = function (version, cb) { if (!this.serviceId) return cb('Failed to clone version. No serviceId configured.'); - var url = this.getFastlyAPIPrefix(this.serviceId, version) + '/clone'; + const url = `${this.getFastlyAPIPrefix(this.serviceId, version)}/clone`; this.request('PUT', url, cb); }; @@ -166,7 +167,7 @@ module.exports = function (apiKey, serviceId) { */ fastly.activateVersion = function (version, cb) { if (!this.serviceId) return cb('Failed to activate version. No serviceId configured.'); - var url = this.getFastlyAPIPrefix(this.serviceId, version) + '/activate'; + const url = `${this.getFastlyAPIPrefix(this.serviceId, version)}/activate`; this.request('PUT', url, cb); }; @@ -184,25 +185,25 @@ module.exports = function (apiKey, serviceId) { return cb('Failed to set response object. No serviceId configured'); } - var url = this.getFastlyAPIPrefix(this.serviceId, version) + '/vcl/' + name; - var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/vcl'; - var content = {content: vcl}; - return this.request('PUT', url, content, function (err, response) { + const url = `${this.getFastlyAPIPrefix(this.serviceId, version)}/vcl/${name}`; + const postUrl = `${this.getFastlyAPIPrefix(this.serviceId, version)}/vcl`; + const content = {content: vcl}; + return this.request('PUT', url, content, (err, response) => { if (err && err.statusCode === 404) { content.name = name; - this.request('POST', postUrl, content, function (e, resp) { + this.request('POST', postUrl, content, (e, resp) => { if (e) { - return cb('Failed while adding custom vcl "' + name + '": ' + e); + return cb(`Failed while adding custom vcl "${name}": ${e}`); } return cb(null, resp); }); return; } if (err) { - return cb('Failed to update custom vcl "' + name + '": ' + err); + return cb(`Failed to update custom vcl "${name}": ${err}`); } return cb(null, response); - }.bind(this)); + }); }; return fastly; diff --git a/dev-server/handler.js b/dev-server/handler.js index 339ceff5c..08e62fd43 100644 --- a/dev-server/handler.js +++ b/dev-server/handler.js @@ -9,7 +9,7 @@ const Handler = function (route) { }; } - var url = '/' + route.name + '.html'; + const url = `/${route.name}.html`; return function (req, res, next) { req.url = url; next(); diff --git a/dev-server/index.js b/dev-server/index.js index 5be0ab295..d16e74dfc 100644 --- a/dev-server/index.js +++ b/dev-server/index.js @@ -1,16 +1,16 @@ -var express = require('express'); -var proxy = require('express-http-proxy'); -var webpackDevMiddleware = require('webpack-dev-middleware'); -var webpack = require('webpack'); +const express = require('express'); +const proxy = require('express-http-proxy'); +const webpackDevMiddleware = require('webpack-dev-middleware'); +const webpack = require('webpack'); -var compiler = webpack(require('../webpack.config.js')); -var handler = require('./handler'); -var log = require('./log'); -var routes = require('../src/routes.json').concat(require('../src/routes-dev.json')) +const compiler = webpack(require('../webpack.config.js')); +const handler = require('./handler'); +const log = require('./log'); +const routes = require('../src/routes.json').concat(require('../src/routes-dev.json')) .filter(route => !process.env.VIEW || process.env.VIEW === route.view); // Create server -var app = express(); +const app = express(); app.disable('x-powered-by'); // Server setup @@ -21,11 +21,11 @@ routes.forEach(route => { app.get(route.pattern, handler(route)); }); -var middlewareOptions = {}; +const middlewareOptions = {}; app.use(webpackDevMiddleware(compiler, middlewareOptions)); -var proxyHost = process.env.FALLBACK || ''; +const proxyHost = process.env.FALLBACK || ''; if (proxyHost !== '') { // Fall back to scratchr2 in development // This proxy middleware must come last @@ -33,10 +33,10 @@ if (proxyHost !== '') { } // Start listening -var port = process.env.PORT || 8333; -app.listen(port, function () { - process.stdout.write('Server listening on port ' + port + '\n'); +const port = process.env.PORT || 8333; +app.listen(port, () => { + process.stdout.write(`Server listening on port ${port}\n`); if (proxyHost) { - process.stdout.write('Proxy host: ' + proxyHost + '\n'); + process.stdout.write(`Proxy host: ${proxyHost}\n`); } }); diff --git a/dev-server/log.js b/dev-server/log.js index 7b9d07064..550d2d4d3 100644 --- a/dev-server/log.js +++ b/dev-server/log.js @@ -1,7 +1,7 @@ -var bunyan = require('bunyan'); +const bunyan = require('bunyan'); module.exports = function () { - var logger = bunyan.createLogger({ + const logger = bunyan.createLogger({ name: 'www', serializers: {req: bunyan.stdSerializers.req} }); diff --git a/webpack.config.js b/webpack.config.js index 497cceda8..4010c6a44 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,8 +13,9 @@ const TerserPlugin = require('terser-webpack-plugin'); // PostCss const autoprefixer = require('autoprefixer'); +/** @type {Array} */ let routes = require('./src/routes.json'); -const templateConfig = require('./src/template-config.js'); // eslint-disable-line global-require +const templateConfig = require('./src/template-config.js'); if (process.env.NODE_ENV !== 'production') { routes = routes.concat(require('./src/routes-dev.json')); // eslint-disable-line global-require @@ -22,10 +23,8 @@ if (process.env.NODE_ENV !== 'production') { routes = routes.filter(route => !process.env.VIEW || process.env.VIEW === route.view); -const pageRoutes = routes.filter(function (route) { - return !route.redirect; -}); -let VersionPlugin = function (options) { +const pageRoutes = routes.filter(route => !route.redirect); +const VersionPlugin = function (options) { this.options = options || {}; return this; }; @@ -44,10 +43,10 @@ VersionPlugin.prototype.apply = function (compiler) { }; const options = this.options; - compiler.plugin('emit', function (compilation, callback) { + compiler.plugin('emit', (compilation, callback) => { const sha = process.env.WWW_VERSION; if (!sha) { // eslint-disable-line no-negated-condition - gitsha(options, function (err, _sha) { + gitsha(options, (err, _sha) => { if (err) return callback(err); return addVersion(compilation, _sha, callback); }); @@ -58,9 +57,9 @@ VersionPlugin.prototype.apply = function (compiler) { }; // Prepare all entry points -let entry = {}; +const entry = {}; -pageRoutes.forEach(function (route) { +pageRoutes.forEach(route => { entry[route.name] = [ './src/init.js', `./src/views/${route.view}.jsx` @@ -167,14 +166,12 @@ module.exports = { new MiniCssExtractPlugin(), new VersionPlugin({length: 5}) ].concat(pageRoutes - .map(function (route) { - return new HtmlWebpackPlugin(defaults({}, { - title: route.title, - filename: route.name + '.html', - route: route, - dynamicMetaTags: route.dynamicMetaTags - }, templateConfig)); - }) + .map(route => new HtmlWebpackPlugin(defaults({}, { + title: route.title, + filename: `${route.name}.html`, + route: route, + dynamicMetaTags: route.dynamicMetaTags + }, templateConfig))) ).concat([ new CopyWebpackPlugin({ patterns: [ @@ -206,16 +203,16 @@ module.exports = { ] }), new webpack.DefinePlugin({ - 'process.env.NODE_ENV': '"' + (process.env.NODE_ENV || 'development') + '"', - 'process.env.API_HOST': '"' + (process.env.API_HOST || 'https://api.scratch.mit.edu') + '"', - 'process.env.RECAPTCHA_SITE_KEY': '"' + - (process.env.RECAPTCHA_SITE_KEY || '6Lf6kK4UAAAAABKTyvdSqgcSVASEnMrCquiAkjVW') + '"', - 'process.env.ASSET_HOST': '"' + (process.env.ASSET_HOST || 'https://assets.scratch.mit.edu') + '"', - 'process.env.BACKPACK_HOST': '"' + (process.env.BACKPACK_HOST || 'https://backpack.scratch.mit.edu') + '"', - 'process.env.CLOUDDATA_HOST': '"' + (process.env.CLOUDDATA_HOST || 'clouddata.scratch.mit.edu') + '"', - 'process.env.PROJECT_HOST': '"' + (process.env.PROJECT_HOST || 'https://projects.scratch.mit.edu') + '"', - 'process.env.STATIC_HOST': '"' + (process.env.STATIC_HOST || 'https://uploads.scratch.mit.edu') + '"', - 'process.env.SCRATCH_ENV': '"' + (process.env.SCRATCH_ENV || 'development') + '"' + 'process.env.NODE_ENV': `"${process.env.NODE_ENV || 'development'}"`, + 'process.env.API_HOST': `"${process.env.API_HOST || 'https://api.scratch.mit.edu'}"`, + 'process.env.RECAPTCHA_SITE_KEY': `"${ + process.env.RECAPTCHA_SITE_KEY || '6Lf6kK4UAAAAABKTyvdSqgcSVASEnMrCquiAkjVW'}"`, + 'process.env.ASSET_HOST': `"${process.env.ASSET_HOST || 'https://assets.scratch.mit.edu'}"`, + 'process.env.BACKPACK_HOST': `"${process.env.BACKPACK_HOST || 'https://backpack.scratch.mit.edu'}"`, + 'process.env.CLOUDDATA_HOST': `"${process.env.CLOUDDATA_HOST || 'clouddata.scratch.mit.edu'}"`, + 'process.env.PROJECT_HOST': `"${process.env.PROJECT_HOST || 'https://projects.scratch.mit.edu'}"`, + 'process.env.STATIC_HOST': `"${process.env.STATIC_HOST || 'https://uploads.scratch.mit.edu'}"`, + 'process.env.SCRATCH_ENV': `"${process.env.SCRATCH_ENV || 'development'}"` }) ]) .concat(process.env.ANALYZE_BUNDLE === 'true' ? [