Skip to content

Commit 19a4787

Browse files
committed
chore: extension registry embed in distributable for better first use UX
1 parent f3f7930 commit 19a4787

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ test/thirdparty/jasmine-reporters
7979
!/src/extensions/dev/README.*
8080

8181
/src/extensions/disabled
82+
/src/extensions/registry
8283

8384
# ignore .disabled file for default extensions
8485
/src/extensions/default/*/.disabled

gulpfile.js/thirdparty-lib-copy.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,37 @@
2222

2323
const { src, dest, series } = require('gulp');
2424
const fs = require("fs");
25+
const path = require('path');
2526

2627
// removed require('merge-stream') node module. it gives wired glob behavior and some files goes missing
2728
const rename = require("gulp-rename");
2829

2930

3031
// individual third party copy
31-
function copyLicence(path, name) {
32+
function copyLicence(filePath, name) {
3233
console.log(`Copying licence file ${name}.markdown`);
33-
return src(path)
34+
return src(filePath)
3435
.pipe(rename(`${name}.markdown`))
3536
.pipe(dest('src/thirdparty/licences/'));
3637
}
3738

38-
function renameFile(path, newName, destPath) {
39-
console.log(`Renaming file ${path} to ${newName}`);
40-
return src(path)
39+
function renameFile(filePath, newName, destPath) {
40+
console.log(`Renaming file ${filePath} to ${newName}`);
41+
return src(filePath)
4142
.pipe(rename(newName))
4243
.pipe(dest(destPath));
4344
}
4445

46+
function ensureDirectoryExists(filePath) {
47+
const dir = path.dirname(filePath);
48+
if (!fs.existsSync(dir)) {
49+
fs.mkdirSync(dir, { recursive: true });
50+
}
51+
}
52+
4553
function downloadFile(url, outputPath) {
54+
console.log(`Downloading file ${url} to ${outputPath}`);
55+
ensureDirectoryExists(outputPath);
4656
return fetch(url)
4757
.then(x => {
4858
if(x.status !== 200){
@@ -76,6 +86,11 @@ function _createListDirJson(dirPath, jsonFileName) {
7686
fs.writeFileSync(`${dirPath}/${jsonFileName}`, JSON.stringify(filenames));
7787
}
7888

89+
function _getConfigJSON() {
90+
let configPath = "src/config.json";
91+
console.log("Reading phoenix Config :", configPath);
92+
return JSON.parse(fs.readFileSync(configPath, "utf8"));
93+
}
7994

8095
/**
8196
* Add thirdparty libs copied to gitignore except the licence file.
@@ -107,6 +122,13 @@ let copyThirdPartyLibs = series(
107122
'src/thirdparty/bugsnag-performance.min.js'),
108123
downloadFile.bind(downloadFile, 'https://d2wy8f7a9ursnm.cloudfront.net/v2/bugsnag-performance.min.js.map',
109124
'src/thirdparty/bugsnag-performance.min.js.map'),
125+
// phoenix extension registry cache for first time load
126+
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry,
127+
'src/extensions/registry/registry.json'),
128+
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry_version,
129+
'src/extensions/registry/registry_version.json'),
130+
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry_popularity,
131+
'src/extensions/registry/popularity.json'),
110132
// tern js
111133
copyFiles.bind(copyFiles, ['node_modules/tern/defs/**/*'], 'src/thirdparty/tern/defs'),
112134
copyFiles.bind(copyFiles, ['node_modules/tern/lib/**/*'], 'src/thirdparty/tern/lib'),

src/extensibility/ExtensionManager.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ define(function (require, exports, module) {
342342
* Downloads the registry of Brackets extensions and stores the information in our
343343
* extension info.
344344
*
345-
* @param {boolean} force - true to fetch registry from server fresh every time
345+
* @param {boolean} [force] - true to fetch registry from server fresh every time
346346
* @return {$.Promise} a promise that's resolved with the registry JSON data
347347
* or rejected if the server can't be reached.
348348
*/
@@ -367,6 +367,7 @@ define(function (require, exports, module) {
367367
if(!pendingDownloadRegistry.alreadyResolvedFromCache){
368368
_populateExtensions(registry);
369369
pendingDownloadRegistry.resolve();
370+
pendingDownloadRegistry.alreadyResolvedFromCache = true;
370371
}
371372
}).finally(()=>{
372373
pendingDownloadRegistry = null;
@@ -386,11 +387,31 @@ define(function (require, exports, module) {
386387
return pendingDownloadRegistry.promise();
387388
}
388389

390+
async function _getLocalRegistry() {
391+
// the extension registry is like 1.5MB. A local copy is packaged in the src/extensions/registry/ folder
392+
// so that on first launch, the user can see the extension manager instantly(though outdated).
393+
// The local registry is created at build time and will get outdated if the user uses an old installer.
394+
// but it will get updated when the user clicks on extension manager.
395+
try {
396+
const response = await fetch("extensions/registry/registry.json");
397+
if (response.ok) {
398+
return await response.json();
399+
} else {
400+
console.error(`Failed to fetch local registry: ${response.status} ${response.statusText}`);
401+
return null;
402+
}
403+
} catch (error) {
404+
console.error(`Error fetching local registry: ${error.message}`);
405+
return null;
406+
}
407+
}
408+
389409
_getCachedRegistry() // never rejects
390410
.then(registryJson => {
391411
if(registryJson) {
392412
// we always immediately but after the promise chain is setup after function return (some bug sigh)
393413
// resolve for ui responsiveness and then check for updates.
414+
console.log("Using cached extension registry");
394415
setTimeout(()=>{
395416
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "registry", "cachedUse");
396417
let registry = JSON.parse(registryJson);
@@ -399,6 +420,19 @@ define(function (require, exports, module) {
399420
pendingDownloadRegistry.resolve();
400421
}, 0);
401422
pendingDownloadRegistry.alreadyResolvedFromCache = true;
423+
} else {
424+
_getLocalRegistry().then(localRegistry => {
425+
if(!localRegistry ||
426+
!pendingDownloadRegistry || pendingDownloadRegistry.alreadyResolvedFromCache) {
427+
return;
428+
}
429+
console.log("Using outdated local extension registry as no cached registry found.");
430+
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "registry", "outdatedUse");
431+
localRegistry = _filterIncompatibleEntries(localRegistry);
432+
_populateExtensions(localRegistry);
433+
pendingDownloadRegistry.resolve();
434+
pendingDownloadRegistry.alreadyResolvedFromCache = true;
435+
});
402436
}
403437
// check for latest updates even if we have cache
404438
_shouldUpdateExtensionRegistry()

0 commit comments

Comments
 (0)