diff --git a/services/web/.gitignore b/services/web/.gitignore index a48481690a..3830036f24 100644 --- a/services/web/.gitignore +++ b/services/web/.gitignore @@ -67,6 +67,10 @@ public/minjs/ Gemfile.lock +public/stylesheets/ol-style.*.css +public/stylesheets/style.*.css + + *.swp .DS_Store diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index c49add4a91..a0000360b3 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -205,12 +205,12 @@ module.exports = (grunt) -> modules: [ { name: "main", - exclude: ["libs"] + exclude: ["libraries"] }, { name: "ide", - exclude: ["libs", "pdfjs-dist/build/pdf"] - }, { - name: "libs" + exclude: ["pdfjs-dist/build/pdf", "libraries"] + },{ + name: "libraries" },{ name: "ace/mode-latex" },{ diff --git a/services/web/app/coffee/infrastructure/ExpressLocals.coffee b/services/web/app/coffee/infrastructure/ExpressLocals.coffee index b126819f56..002a10ca89 100644 --- a/services/web/app/coffee/infrastructure/ExpressLocals.coffee +++ b/services/web/app/coffee/infrastructure/ExpressLocals.coffee @@ -12,7 +12,7 @@ Modules = require "./Modules" Url = require "url" PackageVersions = require "./PackageVersions" htmlEncoder = new require("node-html-encoder").Encoder("numerical") -fingerprints = {} +hashedFiles = {} Path = require 'path' Features = require "./Features" @@ -30,43 +30,39 @@ getFileContent = (filePath)-> filePath = Path.join __dirname, "../../../", "public#{filePath}" exists = fs.existsSync filePath if exists - content = fs.readFileSync filePath + content = fs.readFileSync filePath, "UTF-8" return content else - logger.log filePath:filePath, "file does not exist for fingerprints" + logger.log filePath:filePath, "file does not exist for hashing" return "" -logger.log "Generating file fingerprints..." +logger.log "Generating file hashes..." pathList = [ - ["#{jsPath}libs/#{fineuploader}.js"] - ["#{jsPath}libs/require.js"] - ["#{jsPath}ide.js"] - ["#{jsPath}main.js"] - ["#{jsPath}libs.js"] - ["#{jsPath}#{ace}/ace.js","#{jsPath}#{ace}/mode-latex.js","#{jsPath}#{ace}/worker-latex.js","#{jsPath}#{ace}/snippets/latex.js"] - ["#{jsPath}libs/#{pdfjs}/pdf.js"] - ["#{jsPath}libs/#{pdfjs}/pdf.worker.js"] - ["#{jsPath}libs/#{pdfjs}/compatibility.js"] - ["/stylesheets/style.css"] - ["/stylesheets/ol-style.css"] + "#{jsPath}libs/require.js" + "#{jsPath}ide.js" + "#{jsPath}main.js" + "#{jsPath}libraries.js" + "/stylesheets/style.css" + "/stylesheets/ol-style.css" ] -for paths in pathList - contentList = _.map(paths, getFileContent) - content = contentList.join("") +for path in pathList + content = getFileContent(path) hash = crypto.createHash("md5").update(content).digest("hex") - _.each paths, (filePath)-> - logger.log "#{filePath}: #{hash}" - fingerprints[filePath] = hash + + splitPath = path.split("/") + filenameSplit = splitPath.pop().split(".") + filenameSplit.splice(filenameSplit.length-1, 0, hash) + splitPath.push(filenameSplit.join(".")) -getFingerprint = (path) -> - if fingerprints[path]? - return fingerprints[path] - else - logger.err "No fingerprint for file: #{path}" - return "" + hashPath = splitPath.join("/") + hashedFiles[path] = hashPath -logger.log "Finished generating file fingerprints" + fsHashPath = Path.join __dirname, "../../../", "public#{hashPath}" + fs.writeFileSync(fsHashPath, content) + + +logger.log "Finished hashing static content" cdnAvailable = Settings.cdn?.web?.host? darkCdnAvailable = Settings.cdn?.web?.darkHost? @@ -120,29 +116,35 @@ module.exports = (app, webRouter, privateApiRouter, publicApiRouter)-> res.locals.fullJsPath = Url.resolve(staticFilesBase, jsPath) res.locals.lib = PackageVersions.lib + + res.locals.buildJsPath = (jsFile, opts = {})-> path = Path.join(jsPath, jsFile) - doFingerPrint = opts.fingerprint != false + if opts.hashedPath + path = hashedFiles[path] if !opts.qs? opts.qs = {} - if !opts.qs?.fingerprint? and doFingerPrint - opts.qs.fingerprint = getFingerprint(path) - if opts.cdn != false path = Url.resolve(staticFilesBase, path) qs = querystring.stringify(opts.qs) + if opts.removeExtension == true + path = path.slice(0,-3) + if qs? and qs.length > 0 path = path + "?" + qs return path - res.locals.buildCssPath = (cssFile)-> + res.locals.buildCssPath = (cssFile, opts)-> path = Path.join("/stylesheets/", cssFile) - return Url.resolve(staticFilesBase, path) + "?fingerprint=" + getFingerprint(path) + if opts?.hashedPath + hashedPath = hashedFiles[path] + return Url.resolve(staticFilesBase, hashedPath) + return Url.resolve(staticFilesBase, path) res.locals.buildImgPath = (imgFile)-> path = Path.join("/img/", imgFile) @@ -227,10 +229,6 @@ module.exports = (app, webRouter, privateApiRouter, publicApiRouter)-> return req.query?[field] next() - webRouter.use (req, res, next)-> - res.locals.fingerprint = getFingerprint - next() - webRouter.use (req, res, next)-> res.locals.formatPrice = SubscriptionFormatters.formatPrice next() diff --git a/services/web/app/views/layout.pug b/services/web/app/views/layout.pug index e12d7d6f81..f203d29357 100644 --- a/services/web/app/views/layout.pug +++ b/services/web/app/views/layout.pug @@ -23,7 +23,7 @@ html(itemscope, itemtype='http://schema.org/Product') link(rel="apple-touch-icon-precomposed", href="/" + settings.brandPrefix + "apple-touch-icon-precomposed.png") link(rel="mask-icon", href="/" + settings.brandPrefix + "mask-favicon.svg", color="#a93529") - link(rel='stylesheet', href=buildCssPath("/" + settings.brandPrefix + "style.css")) + link(rel='stylesheet', href=buildCssPath("/" + settings.brandPrefix + "style.css", {hashedPath:true})) block _headLinks @@ -57,7 +57,7 @@ html(itemscope, itemtype='http://schema.org/Product') script(type="text/javascript"). window.csrfToken = "#{csrfToken}"; - script(src=buildJsPath("libs/jquery-1.11.1.min.js", {fingerprint:false})) + script(src=buildJsPath("libs/jquery-1.11.1.min.js")) script(type="text/javascript"). var noCdnKey = "nocdn=true" var cdnBlocked = typeof jQuery === 'undefined' @@ -68,7 +68,7 @@ html(itemscope, itemtype='http://schema.org/Product') block scripts - script(src=buildJsPath("libs/angular-1.6.4.min.js", {fingerprint:false})) + script(src=buildJsPath("libs/angular-1.6.4.min.js")) script. window.sharelatex = { @@ -142,9 +142,10 @@ html(itemscope, itemtype='http://schema.org/Product') window.requirejs = { "paths" : { "moment": "libs/#{lib('moment')}", - "fineuploader": "libs/#{lib('fineuploader')}" + "fineuploader": "libs/#{lib('fineuploader')}", + "main": "#{buildJsPath('main.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}", + "libraries": "#{buildJsPath('libraries.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}", }, - "urlArgs": "fingerprint=#{fingerprint(jsPath + 'main.js')}-#{fingerprint(jsPath + 'libs.js')}", "config":{ "moment":{ "noGlobal": true @@ -152,9 +153,9 @@ html(itemscope, itemtype='http://schema.org/Product') } }; script( - data-main=buildJsPath('main.js', {fingerprint:false}), + data-main=buildJsPath('main.js', {hashedPath:false}), baseurl=fullJsPath, - src=buildJsPath('libs/require.js') + src=buildJsPath('libs/require.js', {hashedPath:true}) ) include contact-us-modal diff --git a/services/web/app/views/project/editor.pug b/services/web/app/views/project/editor.pug index ec1d129714..d1d0d94cf3 100644 --- a/services/web/app/views/project/editor.pug +++ b/services/web/app/views/project/editor.pug @@ -98,9 +98,9 @@ block requirejs script(type="text/javascript" src='/socket.io/socket.io.js') //- don't use cdn for workers - - var aceWorkerPath = buildJsPath(lib('ace'), {cdn:false,fingerprint:false}) - - var pdfWorkerPath = buildJsPath('/libs/' + lib('pdfjs') + '/pdf.worker', {cdn:false,fingerprint:false}) - - var pdfCMapsPath = buildJsPath('/libs/' + lib('pdfjs') + '/bcmaps/', {cdn:false,fingerprint:false}) + - var aceWorkerPath = buildJsPath(lib('ace'), {cdn:false}) + - var pdfWorkerPath = buildJsPath('/libs/' + lib('pdfjs') + '/pdf.worker', {cdn:false}) + - var pdfCMapsPath = buildJsPath('/libs/' + lib('pdfjs') + '/bcmaps/', {cdn:false}) //- We need to do .replace(/\//g, '\\/') do that '' -> '<\/script>' //- and doesn't prematurely end the script tag. @@ -126,14 +126,15 @@ block requirejs window.wikiEnabled = #{!!(settings.apis.wiki && settings.apis.wiki.url)}; window.requirejs = { "paths" : { - "mathjax": "#{buildJsPath('/libs/mathjax/MathJax.js', {cdn:false, fingerprint:false, qs:{config:'TeX-AMS_HTML'}})}", + "mathjax": "#{buildJsPath('/libs/mathjax/MathJax.js', {cdn:false, qs:{config:'TeX-AMS_HTML'}})}", "moment": "libs/#{lib('moment')}", "pdfjs-dist/build/pdf": "libs/#{lib('pdfjs')}/pdf", "pdfjs-dist/build/pdf.worker": "#{pdfWorkerPath}", "ace": "#{lib('ace')}", - "fineuploader": "libs/#{lib('fineuploader')}" + "fineuploader": "libs/#{lib('fineuploader')}", + "ide": "#{buildJsPath('ide.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}", + "libraries": "#{buildJsPath('libraries.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}", }, - "urlArgs" : "fingerprint=#{fingerprint(jsPath + 'ide.js')}-#{fingerprint(jsPath + 'libs.js')}", "waitSeconds": 0, "shim": { "pdfjs-dist/build/pdf": { @@ -155,14 +156,13 @@ block requirejs } } }; - window.aceFingerprint = "#{fingerprint(jsPath + lib('ace') + '/ace.js')}" window.aceWorkerPath = "#{aceWorkerPath}"; window.pdfCMapsPath = "#{pdfCMapsPath}" window.uiConfig = JSON.parse('!{JSON.stringify(uiConfig).replace(/\//g, "\\/")}'); script( - data-main=buildJsPath("ide.js", {fingerprint:false}), + data-main=buildJsPath("ide.js", {hashedPath:false}), baseurl=fullJsPath, - data-ace-base=buildJsPath(lib('ace'), {fingerprint:false}), - src=buildJsPath('libs/require.js') + data-ace-base=buildJsPath(lib('ace')), + src=buildJsPath('libs/require.js', {hashedPath:true}) ) diff --git a/services/web/public/coffee/base.coffee b/services/web/public/coffee/base.coffee index 03d0ada365..c3847c9342 100644 --- a/services/web/public/coffee/base.coffee +++ b/services/web/public/coffee/base.coffee @@ -1,5 +1,5 @@ define [ - "libs" + "libraries" "modules/recursionHelper" "modules/errorCatcher" "modules/localStorage" diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 6908b25bce..ff5d1554e2 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -33,7 +33,7 @@ define [ if !ace.config._moduleUrl? ace.config._moduleUrl = ace.config.moduleUrl ace.config.moduleUrl = (args...) -> - url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}" + url = ace.config._moduleUrl(args...) return url App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, metadata, graphics, preamble, files, $http, $q) -> diff --git a/services/web/public/coffee/libs.coffee b/services/web/public/coffee/libraries.coffee similarity index 100% rename from services/web/public/coffee/libs.coffee rename to services/web/public/coffee/libraries.coffee diff --git a/services/web/public/coffee/utils/underscore.coffee b/services/web/public/coffee/utils/underscore.coffee index 7a1551f90b..944abccb5d 100644 --- a/services/web/public/coffee/utils/underscore.coffee +++ b/services/web/public/coffee/utils/underscore.coffee @@ -1,5 +1,5 @@ define [ - "libs" + "libraries" ], () -> angular.module('underscore', []).factory '_', -> return window._