Skip to content

Commit 8041754

Browse files
authored
feat: STRF-13399 If theme doesn't have stencil.conf.js, download it from cornerstone (#1271)
1 parent b329fbc commit 8041754

File tree

4 files changed

+60
-5
lines changed

4 files changed

+60
-5
lines changed

lib/BuildConfigManager.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import { createRequire } from 'node:module';
66
import { THEME_PATH } from '../constants.js';
77

88
const require = createRequire(import.meta.url);
9+
const isJest = typeof process !== 'undefined' && 'JEST_WORKER_ID' in process.env;
10+
11+
const cornerstoneConfigLink = isJest
12+
? 'https://raw.githubusercontent.com/bigcommerce/stencil-cli/master/test/_mocks/build-config/valid-config/stencil.conf.cjs'
13+
: 'https://raw.githubusercontent.com/bigcommerce/cornerstone/master/stencil.conf.cjs';
914

1015
class BuildConfigManager {
1116
constructor({ workDir = THEME_PATH, fs = fsModule, timeout = 20000 } = {}) {
@@ -19,7 +24,10 @@ class BuildConfigManager {
1924
this._worker = null;
2025
this._workerIsReady = false;
2126
this.timeout = timeout;
22-
const config = this._getConfig(this._buildConfigPath, this._oldBuildConfigPath);
27+
}
28+
29+
async initConfig() {
30+
const config = await this._getConfig(this._buildConfigPath, this._oldBuildConfigPath);
2331
this.development = config.development || this._devWorker;
2432
this.production = config.production || this._prodWorker;
2533
this.watchOptions = config.watchOptions;
@@ -42,7 +50,7 @@ class BuildConfigManager {
4250
this._worker.kill(signal);
4351
}
4452

45-
_getConfig(configPath, oldConfigPath) {
53+
async _getConfig(configPath, oldConfigPath) {
4654
if (this._fs.existsSync(configPath)) {
4755
// eslint-disable-next-line import/no-dynamic-require
4856
return require(configPath);
@@ -52,7 +60,28 @@ class BuildConfigManager {
5260
// eslint-disable-next-line import/no-dynamic-require
5361
return require(configPath);
5462
}
55-
return {};
63+
64+
// Fallback to cornerstone default stencil.conf.cjs
65+
const content = await this.downloadFileFromGitHub(cornerstoneConfigLink);
66+
this._fs.writeFileSync(configPath, content);
67+
68+
// eslint-disable-next-line import/no-dynamic-require
69+
return require(configPath);
70+
}
71+
72+
async downloadFileFromGitHub(rawUrl) {
73+
try {
74+
const response = await fetch(rawUrl);
75+
76+
if (!response.ok) {
77+
console.log(`Failed to fetch file from ${rawUrl}: ${response.statusText}`);
78+
}
79+
80+
return response.text();
81+
} catch (error) {
82+
console.error('Failed to fetch stencil.conf.cjs:', error);
83+
return null;
84+
}
5685
}
5786

5887
_moveOldConfig(newPath, oldPath) {

lib/BuildConfigManager.spec.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fs from 'fs/promises';
12
import { jest } from '@jest/globals';
23
import { promisify } from 'util';
34
import BuildConfigManager from './BuildConfigManager.js';
@@ -8,10 +9,11 @@ describe('BuildConfigManager integration tests', () => {
89
jest.restoreAllMocks();
910
});
1011
describe('constructor', () => {
11-
it('should return an instance with correct watchOptions taken from the config file', () => {
12+
it('should return an instance with correct watchOptions taken from the config file', async () => {
1213
const buildConfig = new BuildConfigManager({
1314
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
1415
});
16+
await buildConfig.initConfig();
1517
expect(buildConfig.watchOptions).toBeInstanceOf(Object);
1618
expect(buildConfig.watchOptions.files).toBeInstanceOf(Array);
1719
expect(buildConfig.watchOptions.ignored).toBeInstanceOf(Array);
@@ -22,6 +24,7 @@ describe('BuildConfigManager integration tests', () => {
2224
const buildConfig = new BuildConfigManager({
2325
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
2426
});
27+
await buildConfig.initConfig();
2528
buildConfig.initWorker();
2629
expect(buildConfig.production).toBeInstanceOf(Function);
2730
await promisify(buildConfig.production.bind(buildConfig))();
@@ -31,6 +34,7 @@ describe('BuildConfigManager integration tests', () => {
3134
const buildConfig = new BuildConfigManager({
3235
workDir: `${cwd}/test/_mocks/build-config/legacy-config`,
3336
});
37+
await buildConfig.initConfig();
3438
buildConfig.initWorker();
3539
expect(buildConfig.production).toBeInstanceOf(Function);
3640
await promisify(buildConfig.production.bind(buildConfig))();
@@ -40,19 +44,38 @@ describe('BuildConfigManager integration tests', () => {
4044
const buildConfig = new BuildConfigManager({
4145
workDir: `${cwd}/test/_mocks/build-config/noworker-config`,
4246
});
47+
await buildConfig.initConfig();
4348
const initedBuildConfig = buildConfig.initWorker();
4449
expect(buildConfig.production).toBeInstanceOf(Function);
4550
await expect(
4651
promisify(initedBuildConfig.production.bind(initedBuildConfig))(),
4752
).rejects.toContain('worker terminated');
4853
buildConfig.stopWorker();
4954
});
55+
it('should download config from cornerstone github', async () => {
56+
const workDir = `${cwd}/test/_mocks/build-config/no-config`;
57+
const buildConfig = new BuildConfigManager({
58+
workDir,
59+
});
60+
try {
61+
await fs.access(workDir);
62+
} catch (e) {
63+
await fs.mkdir(workDir, { recursive: true });
64+
}
65+
await buildConfig.initConfig();
66+
buildConfig.initWorker();
67+
expect(buildConfig.production).toBeInstanceOf(Function);
68+
await promisify(buildConfig.production.bind(buildConfig))();
69+
buildConfig.stopWorker();
70+
await fs.rm(`${cwd}/test/_mocks/build-config/no-config/stencil.conf.cjs`);
71+
});
5072
});
5173
describe('development method', () => {
5274
it('should reload the browser when a message "reload" is received from stencil.conf.js (valid-config)', async () => {
5375
const buildConfig = new BuildConfigManager({
5476
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
5577
});
78+
await buildConfig.initConfig();
5679
expect(buildConfig.development).toBeInstanceOf(Function);
5780
await new Promise((done) => buildConfig.initWorker().development({ reload: done }));
5881
buildConfig.stopWorker();
@@ -61,6 +84,7 @@ describe('BuildConfigManager integration tests', () => {
6184
const buildConfig = new BuildConfigManager({
6285
workDir: `${cwd}/test/_mocks/build-config/legacy-config`,
6386
});
87+
await buildConfig.initConfig();
6488
expect(buildConfig.development).toBeInstanceOf(Function);
6589
await new Promise((done) => buildConfig.initWorker().development({ reload: done }));
6690
buildConfig.stopWorker();

lib/stencil-bundle.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ class Bundle {
6868
tasks.schemaTranslations = this.assembleSchemaTranslations.bind(this);
6969
tasks.stencilContext = this.assembleStencilContextTask.bind(this);
7070
if (typeof buildConfigManager.production === 'function') {
71-
tasks.theme = (callback) => {
71+
tasks.theme = async (callback) => {
7272
console.log('Theme task Started...');
73+
await buildConfigManager.initConfig();
7374
buildConfigManager.initWorker().production((err) => {
7475
if (err) {
7576
return callback(err);

lib/stencil-start.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class StencilStart {
233233
}
234234
});
235235
if (this._buildConfigManager.development) {
236+
await this._buildConfigManager.initConfig();
236237
this._buildConfigManager.initWorker().development(this._browserSync);
237238
}
238239
await this.checkLangFiles(langsPath, this._storeSettingsLocale.default_shopper_language);

0 commit comments

Comments
 (0)