mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
Merge pull request #14038 from atom/as-ns-optimize-stylesheets-loading
Optimize style sheets loading
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
"jasmine-tagged": "^1.1.4",
|
||||
"jquery": "2.1.4",
|
||||
"key-path-helpers": "^0.4.0",
|
||||
"less-cache": "1.0.0",
|
||||
"less-cache": "1.1.0",
|
||||
"line-top-index": "0.2.0",
|
||||
"marked": "^0.3.6",
|
||||
"minimatch": "^3.0.3",
|
||||
|
||||
@@ -26,7 +26,8 @@ module.exports = {
|
||||
repositoryRootPath, apmRootPath, scriptRootPath,
|
||||
buildOutputPath, docsOutputPath, intermediateAppPath, symbolsPath,
|
||||
electronDownloadPath, atomHomeDirPath, homeDirPath,
|
||||
getApmBinPath, getNpmBinPath
|
||||
getApmBinPath, getNpmBinPath,
|
||||
snapshotAuxiliaryData: {}
|
||||
}
|
||||
|
||||
function getChannel () {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const CSON = require('season')
|
||||
const deprecatedPackagesMetadata = require('../deprecated-packages')
|
||||
const fs = require('fs-extra')
|
||||
const fs = require('fs-plus')
|
||||
const normalizePackageData = require('normalize-package-data')
|
||||
const path = require('path')
|
||||
const semver = require('semver')
|
||||
@@ -76,6 +76,26 @@ function buildBundledPackagesMetadata () {
|
||||
}
|
||||
}
|
||||
|
||||
const packageStyleSheetsPath = path.join(packagePath, 'styles')
|
||||
let styleSheets = null
|
||||
if (packageMetadata.mainStyleSheet) {
|
||||
styleSheets = [fs.resolve(packagePath, packageMetadata.mainStyleSheet)]
|
||||
} else if (packageMetadata.styleSheets) {
|
||||
styleSheets = packageMetadata.styleSheets.map((name) => (
|
||||
fs.resolve(packageStyleSheetsPath, name, ['css', 'less', ''])
|
||||
))
|
||||
} else {
|
||||
const indexStylesheet = fs.resolve(packagePath, 'index', ['css', 'less'])
|
||||
if (indexStylesheet) {
|
||||
styleSheets = [indexStylesheet]
|
||||
} else {
|
||||
styleSheets = fs.listSync(packageStyleSheetsPath, ['css', 'less'])
|
||||
}
|
||||
}
|
||||
|
||||
packageNewMetadata.styleSheetPaths =
|
||||
styleSheets.map(styleSheetPath => path.relative(packagePath, styleSheetPath))
|
||||
|
||||
packages[packageMetadata.name] = packageNewMetadata
|
||||
if (packageModuleCache.extensions) {
|
||||
for (let extension of Object.keys(packageModuleCache.extensions)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = function (packagedAppPath) {
|
||||
baseDirPath,
|
||||
mainPath: path.resolve(baseDirPath, '..', 'src', 'initialize-application-window.js'),
|
||||
cachePath: path.join(CONFIG.atomHomeDirPath, 'snapshot-cache'),
|
||||
auxiliaryData: CONFIG.snapshotAuxiliaryData,
|
||||
shouldExcludeModule: (modulePath) => {
|
||||
if (processedFiles > 0) {
|
||||
process.stdout.write('\r')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const klawSync = require('klaw-sync')
|
||||
const glob = require('glob')
|
||||
const path = require('path')
|
||||
const LessCache = require('less-cache')
|
||||
@@ -28,6 +29,18 @@ module.exports = function () {
|
||||
}
|
||||
}
|
||||
|
||||
CONFIG.snapshotAuxiliaryData.lessSourcesByRelativeFilePath = {}
|
||||
function saveIntoSnapshotAuxiliaryData (absoluteFilePath, content) {
|
||||
const relativeFilePath = path.relative(CONFIG.intermediateAppPath, absoluteFilePath)
|
||||
if (!CONFIG.snapshotAuxiliaryData.lessSourcesByRelativeFilePath.hasOwnProperty(relativeFilePath)) {
|
||||
CONFIG.snapshotAuxiliaryData.lessSourcesByRelativeFilePath[relativeFilePath] = {
|
||||
content: content,
|
||||
digest: LessCache.digestForContent(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CONFIG.snapshotAuxiliaryData.importedFilePathsByRelativeImportPath = {}
|
||||
// Warm cache for every combination of the default UI and syntax themes,
|
||||
// because themes assign variables which may be used in any style sheet.
|
||||
for (let uiTheme of uiThemes) {
|
||||
@@ -46,12 +59,26 @@ module.exports = function () {
|
||||
]
|
||||
})
|
||||
|
||||
// Store file paths located at the import paths so that we can avoid scanning them at runtime.
|
||||
for (const absoluteImportPath of lessCache.getImportPaths()) {
|
||||
const relativeImportPath = path.relative(CONFIG.intermediateAppPath, absoluteImportPath)
|
||||
if (!CONFIG.snapshotAuxiliaryData.importedFilePathsByRelativeImportPath.hasOwnProperty(relativeImportPath)) {
|
||||
CONFIG.snapshotAuxiliaryData.importedFilePathsByRelativeImportPath[relativeImportPath] = []
|
||||
for (const importedFile of klawSync(absoluteImportPath, {nodir: true})) {
|
||||
CONFIG.snapshotAuxiliaryData.importedFilePathsByRelativeImportPath[relativeImportPath].push(
|
||||
path.relative(CONFIG.intermediateAppPath, importedFile.path)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cacheCompiledCSS(lessFilePath, importFallbackVariables) {
|
||||
let lessSource = fs.readFileSync(lessFilePath, 'utf8')
|
||||
if (importFallbackVariables) {
|
||||
lessSource = FALLBACK_VARIABLE_IMPORTS + lessSource
|
||||
}
|
||||
lessCache.cssForFile(lessFilePath, lessSource)
|
||||
saveIntoSnapshotAuxiliaryData(lessFilePath, lessSource)
|
||||
}
|
||||
|
||||
// Cache all styles in static; don't append variable imports
|
||||
@@ -69,10 +96,24 @@ module.exports = function () {
|
||||
// Cache styles for this UI theme
|
||||
const uiThemeMainPath = path.join(CONFIG.intermediateAppPath, 'node_modules', uiTheme, 'index.less')
|
||||
cacheCompiledCSS(uiThemeMainPath, true)
|
||||
for (let lessFilePath of glob.sync(path.join(CONFIG.intermediateAppPath, 'node_modules', uiTheme, '**', '*.less'))) {
|
||||
if (lessFilePath !== uiThemeMainPath) {
|
||||
saveIntoSnapshotAuxiliaryData(lessFilePath, fs.readFileSync(lessFilePath, 'utf8'))
|
||||
}
|
||||
}
|
||||
|
||||
// Cache styles for this syntax theme
|
||||
const syntaxThemeMainPath = path.join(CONFIG.intermediateAppPath, 'node_modules', syntaxTheme, 'index.less')
|
||||
cacheCompiledCSS(syntaxThemeMainPath, true)
|
||||
for (let lessFilePath of glob.sync(path.join(CONFIG.intermediateAppPath, 'node_modules', syntaxTheme, '**', '*.less'))) {
|
||||
if (lessFilePath !== syntaxThemeMainPath) {
|
||||
saveIntoSnapshotAuxiliaryData(lessFilePath, fs.readFileSync(lessFilePath, 'utf8'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let lessFilePath of glob.sync(path.join(CONFIG.intermediateAppPath, 'node_modules', 'atom-ui', '**', '*.less'))) {
|
||||
saveIntoSnapshotAuxiliaryData(lessFilePath, fs.readFileSync(lessFilePath, 'utf8'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"fs-extra": "0.30.0",
|
||||
"glob": "7.0.3",
|
||||
"joanna": "0.0.8",
|
||||
"klaw-sync": "^1.1.2",
|
||||
"legal-eagle": "0.14.0",
|
||||
"lodash.template": "4.4.0",
|
||||
"minidump": "0.9.0",
|
||||
|
||||
@@ -232,7 +232,7 @@ class AtomEnvironment extends Model
|
||||
|
||||
@styles.initialize({@configDirPath})
|
||||
@packages.initialize({devMode, @configDirPath, resourcePath, safeMode})
|
||||
@themes.initialize({@configDirPath, resourcePath, safeMode})
|
||||
@themes.initialize({@configDirPath, resourcePath, safeMode, devMode})
|
||||
|
||||
@commandInstaller.initialize(@getVersion())
|
||||
@workspace.initialize()
|
||||
|
||||
@@ -4,9 +4,9 @@ LessCache = require 'less-cache'
|
||||
# {LessCache} wrapper used by {ThemeManager} to read stylesheets.
|
||||
module.exports =
|
||||
class LessCompileCache
|
||||
@cacheDir: path.join(process.env.ATOM_HOME, 'compile-cache', 'less')
|
||||
constructor: ({resourcePath, importPaths, lessSourcesByRelativeFilePath, importedFilePathsByRelativeImportPath}) ->
|
||||
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache', 'less')
|
||||
|
||||
constructor: ({resourcePath, importPaths}) ->
|
||||
@lessSearchPaths = [
|
||||
path.join(resourcePath, 'static', 'variables')
|
||||
path.join(resourcePath, 'static')
|
||||
@@ -17,11 +17,14 @@ class LessCompileCache
|
||||
else
|
||||
importPaths = @lessSearchPaths
|
||||
|
||||
@cache = new LessCache
|
||||
cacheDir: @constructor.cacheDir
|
||||
importPaths: importPaths
|
||||
resourcePath: resourcePath
|
||||
@cache = new LessCache({
|
||||
importPaths,
|
||||
resourcePath,
|
||||
lessSourcesByRelativeFilePath,
|
||||
importedFilePathsByRelativeImportPath,
|
||||
cacheDir,
|
||||
fallbackDir: path.join(resourcePath, 'less-compile-cache')
|
||||
})
|
||||
|
||||
setImportPaths: (importPaths=[]) ->
|
||||
@cache.setImportPaths(importPaths.concat(@lessSearchPaths))
|
||||
@@ -29,5 +32,5 @@ class LessCompileCache
|
||||
read: (stylesheetPath) ->
|
||||
@cache.readFileSync(stylesheetPath)
|
||||
|
||||
cssForFile: (stylesheetPath, lessContent) ->
|
||||
@cache.cssForFile(stylesheetPath, lessContent)
|
||||
cssForFile: (stylesheetPath, lessContent, digest) ->
|
||||
@cache.cssForFile(stylesheetPath, lessContent, digest)
|
||||
|
||||
@@ -204,7 +204,17 @@ class Package
|
||||
else
|
||||
context = undefined
|
||||
|
||||
@stylesheetDisposables.add(@styleManager.addStyleSheet(source, {sourcePath, priority, context}))
|
||||
@stylesheetDisposables.add(
|
||||
@styleManager.addStyleSheet(
|
||||
source,
|
||||
{
|
||||
sourcePath,
|
||||
priority,
|
||||
context,
|
||||
skipDeprecatedSelectorsTransformation: @bundledPackage
|
||||
}
|
||||
)
|
||||
)
|
||||
@stylesheetsActivated = true
|
||||
|
||||
activateResources: ->
|
||||
@@ -348,15 +358,19 @@ class Package
|
||||
path.join(@path, 'styles')
|
||||
|
||||
getStylesheetPaths: ->
|
||||
stylesheetDirPath = @getStylesheetsPath()
|
||||
if @metadata.mainStyleSheet
|
||||
[fs.resolve(@path, @metadata.mainStyleSheet)]
|
||||
else if @metadata.styleSheets
|
||||
@metadata.styleSheets.map (name) -> fs.resolve(stylesheetDirPath, name, ['css', 'less', ''])
|
||||
else if indexStylesheet = fs.resolve(@path, 'index', ['css', 'less'])
|
||||
[indexStylesheet]
|
||||
if @bundledPackage and @packageManager.packagesCache[@name]?.styleSheetPaths?
|
||||
styleSheetPaths = @packageManager.packagesCache[@name].styleSheetPaths
|
||||
styleSheetPaths.map (styleSheetPath) => path.join(@path, styleSheetPath)
|
||||
else
|
||||
fs.listSync(stylesheetDirPath, ['css', 'less'])
|
||||
stylesheetDirPath = @getStylesheetsPath()
|
||||
if @metadata.mainStyleSheet
|
||||
[fs.resolve(@path, @metadata.mainStyleSheet)]
|
||||
else if @metadata.styleSheets
|
||||
@metadata.styleSheets.map (name) -> fs.resolve(stylesheetDirPath, name, ['css', 'less', ''])
|
||||
else if indexStylesheet = fs.resolve(@path, 'index', ['css', 'less'])
|
||||
[indexStylesheet]
|
||||
else
|
||||
fs.listSync(stylesheetDirPath, ['css', 'less'])
|
||||
|
||||
loadGrammarsSync: ->
|
||||
return if @grammarsLoaded
|
||||
|
||||
@@ -137,29 +137,17 @@ module.exports = class StyleManager {
|
||||
}
|
||||
}
|
||||
|
||||
let transformed
|
||||
if (this.cacheDirPath != null) {
|
||||
const hash = crypto.createHash('sha1')
|
||||
if (params.context != null) {
|
||||
hash.update(params.context)
|
||||
}
|
||||
hash.update(source)
|
||||
const cacheFilePath = path.join(this.cacheDirPath, hash.digest('hex'))
|
||||
try {
|
||||
transformed = JSON.parse(fs.readFileSync(cacheFilePath))
|
||||
} catch (e) {
|
||||
transformed = transformDeprecatedShadowDOMSelectors(source, params.context)
|
||||
fs.writeFileSync(cacheFilePath, JSON.stringify(transformed))
|
||||
}
|
||||
if (params.skipDeprecatedSelectorsTransformation) {
|
||||
styleElement.textContent = source
|
||||
} else {
|
||||
transformed = transformDeprecatedShadowDOMSelectors(source, params.context)
|
||||
const transformed = this.upgradeDeprecatedSelectorsForStyleSheet(source, params.context)
|
||||
styleElement.textContent = transformed.source
|
||||
if (transformed.deprecationMessage) {
|
||||
this.deprecationsBySourcePath[params.sourcePath] = {message: transformed.deprecationMessage}
|
||||
this.emitter.emit('did-update-deprecations')
|
||||
}
|
||||
}
|
||||
|
||||
styleElement.textContent = transformed.source
|
||||
if (transformed.deprecationMessage) {
|
||||
this.deprecationsBySourcePath[params.sourcePath] = {message: transformed.deprecationMessage}
|
||||
this.emitter.emit('did-update-deprecations')
|
||||
}
|
||||
if (updated) {
|
||||
this.emitter.emit('did-update-style-element', styleElement)
|
||||
} else {
|
||||
@@ -171,9 +159,10 @@ module.exports = class StyleManager {
|
||||
addStyleElement (styleElement) {
|
||||
let insertIndex = this.styleElements.length
|
||||
if (styleElement.priority != null) {
|
||||
for (let [index, existingElement] of this.styleElements.entries()) {
|
||||
for (let i = 0; i < this.styleElements.length; i++) {
|
||||
const existingElement = this.styleElements[i]
|
||||
if (existingElement.priority > styleElement.priority) {
|
||||
insertIndex = index
|
||||
insertIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -197,6 +186,26 @@ module.exports = class StyleManager {
|
||||
}
|
||||
}
|
||||
|
||||
upgradeDeprecatedSelectorsForStyleSheet (styleSheet, context) {
|
||||
if (this.cacheDirPath != null) {
|
||||
const hash = crypto.createHash('sha1')
|
||||
if (context != null) {
|
||||
hash.update(context)
|
||||
}
|
||||
hash.update(styleSheet)
|
||||
const cacheFilePath = path.join(this.cacheDirPath, hash.digest('hex'))
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(cacheFilePath))
|
||||
} catch (e) {
|
||||
const transformed = transformDeprecatedShadowDOMSelectors(styleSheet, context)
|
||||
fs.writeFileSync(cacheFilePath, JSON.stringify(transformed))
|
||||
return transformed
|
||||
}
|
||||
} else {
|
||||
return transformDeprecatedShadowDOMSelectors(styleSheet, context)
|
||||
}
|
||||
}
|
||||
|
||||
getDeprecations () {
|
||||
return this.deprecationsBySourcePath
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ _ = require 'underscore-plus'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
{File} = require 'pathwatcher'
|
||||
fs = require 'fs-plus'
|
||||
LessCompileCache = require './less-compile-cache'
|
||||
|
||||
# Extended: Handles loading and activating available themes.
|
||||
#
|
||||
@@ -18,7 +19,14 @@ class ThemeManager
|
||||
@packageManager.onDidActivateInitialPackages =>
|
||||
@onDidChangeActiveThemes => @packageManager.reloadActivePackageStyleSheets()
|
||||
|
||||
initialize: ({@resourcePath, @configDirPath, @safeMode}) ->
|
||||
initialize: ({@resourcePath, @configDirPath, @safeMode, devMode}) ->
|
||||
@lessSourcesByRelativeFilePath = null
|
||||
if devMode or typeof snapshotAuxiliaryData is 'undefined'
|
||||
@lessSourcesByRelativeFilePath = {}
|
||||
@importedFilePathsByRelativeImportPath = {}
|
||||
else
|
||||
@lessSourcesByRelativeFilePath = snapshotAuxiliaryData.lessSourcesByRelativeFilePath
|
||||
@importedFilePathsByRelativeImportPath = snapshotAuxiliaryData.importedFilePathsByRelativeImportPath
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
@@ -126,10 +134,10 @@ class ThemeManager
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# required stylesheet.
|
||||
requireStylesheet: (stylesheetPath) ->
|
||||
requireStylesheet: (stylesheetPath, priority, skipDeprecatedSelectorsTransformation) ->
|
||||
if fullPath = @resolveStylesheet(stylesheetPath)
|
||||
content = @loadStylesheet(fullPath)
|
||||
@applyStylesheet(fullPath, content)
|
||||
@applyStylesheet(fullPath, content, priority, skipDeprecatedSelectorsTransformation)
|
||||
else
|
||||
throw new Error("Could not find a file at path '#{stylesheetPath}'")
|
||||
|
||||
@@ -175,9 +183,7 @@ class ThemeManager
|
||||
@reloadBaseStylesheets()
|
||||
|
||||
reloadBaseStylesheets: ->
|
||||
@requireStylesheet('../static/atom')
|
||||
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
|
||||
@requireStylesheet(nativeStylesheetPath)
|
||||
@requireStylesheet('../static/atom', -2, true)
|
||||
|
||||
stylesheetElementForId: (id) ->
|
||||
escapedId = id.replace(/\\/g, '\\\\')
|
||||
@@ -196,9 +202,12 @@ class ThemeManager
|
||||
fs.readFileSync(stylesheetPath, 'utf8')
|
||||
|
||||
loadLessStylesheet: (lessStylesheetPath, importFallbackVariables=false) ->
|
||||
unless @lessCache?
|
||||
LessCompileCache = require './less-compile-cache'
|
||||
@lessCache = new LessCompileCache({@resourcePath, importPaths: @getImportPaths()})
|
||||
@lessCache ?= new LessCompileCache({
|
||||
@resourcePath,
|
||||
@lessSourcesByRelativeFilePath,
|
||||
@importedFilePathsByRelativeImportPath,
|
||||
importPaths: @getImportPaths()
|
||||
})
|
||||
|
||||
try
|
||||
if importFallbackVariables
|
||||
@@ -206,8 +215,16 @@ class ThemeManager
|
||||
@import "variables/ui-variables";
|
||||
@import "variables/syntax-variables";
|
||||
"""
|
||||
less = fs.readFileSync(lessStylesheetPath, 'utf8')
|
||||
@lessCache.cssForFile(lessStylesheetPath, [baseVarImports, less].join('\n'))
|
||||
relativeFilePath = path.relative(@resourcePath, lessStylesheetPath)
|
||||
lessSource = @lessSourcesByRelativeFilePath[relativeFilePath]
|
||||
if lessSource?
|
||||
content = lessSource.content
|
||||
digest = lessSource.digest
|
||||
else
|
||||
content = baseVarImports + '\n' + fs.readFileSync(lessStylesheetPath, 'utf8')
|
||||
digest = null
|
||||
|
||||
@lessCache.cssForFile(lessStylesheetPath, content, digest)
|
||||
else
|
||||
@lessCache.read(lessStylesheetPath)
|
||||
catch error
|
||||
@@ -231,8 +248,15 @@ class ThemeManager
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
@styleSheetDisposablesBySourcePath[stylesheetPath]?.dispose()
|
||||
|
||||
applyStylesheet: (path, text) ->
|
||||
@styleSheetDisposablesBySourcePath[path] = @styleManager.addStyleSheet(text, sourcePath: path)
|
||||
applyStylesheet: (path, text, priority, skipDeprecatedSelectorsTransformation) ->
|
||||
@styleSheetDisposablesBySourcePath[path] = @styleManager.addStyleSheet(
|
||||
text,
|
||||
{
|
||||
priority,
|
||||
skipDeprecatedSelectorsTransformation,
|
||||
sourcePath: path
|
||||
}
|
||||
)
|
||||
|
||||
activateThemes: ->
|
||||
new Promise (resolve) =>
|
||||
|
||||
@@ -59,7 +59,7 @@ class WorkspaceElement extends HTMLElement {
|
||||
font-family: ${this.config.get('editor.fontFamily')};
|
||||
line-height: ${this.config.get('editor.lineHeight')};
|
||||
}`
|
||||
this.styles.addStyleSheet(styleSheetSource, {sourcePath: 'global-text-editor-styles'})
|
||||
this.styles.addStyleSheet(styleSheetSource, {sourcePath: 'global-text-editor-styles', priority: -1})
|
||||
this.views.performDocumentPoll()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user