Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions lib/BuildConfigManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import { createRequire } from 'node:module';
import { THEME_PATH } from '../constants.js';

const require = createRequire(import.meta.url);
const isJest = typeof process !== 'undefined' && 'JEST_WORKER_ID' in process.env;

const cornerstoneConfigLink = isJest
? 'https://raw.githubusercontent.com/bigcommerce/stencil-cli/master/test/_mocks/build-config/valid-config/stencil.conf.cjs'
: 'https://raw.githubusercontent.com/bigcommerce/cornerstone/master/stencil.conf.cjs';

class BuildConfigManager {
constructor({ workDir = THEME_PATH, fs = fsModule, timeout = 20000 } = {}) {
Expand All @@ -19,7 +24,10 @@ class BuildConfigManager {
this._worker = null;
this._workerIsReady = false;
this.timeout = timeout;
const config = this._getConfig(this._buildConfigPath, this._oldBuildConfigPath);
}

async initConfig() {
const config = await this._getConfig(this._buildConfigPath, this._oldBuildConfigPath);
this.development = config.development || this._devWorker;
this.production = config.production || this._prodWorker;
this.watchOptions = config.watchOptions;
Expand All @@ -42,7 +50,7 @@ class BuildConfigManager {
this._worker.kill(signal);
}

_getConfig(configPath, oldConfigPath) {
async _getConfig(configPath, oldConfigPath) {
if (this._fs.existsSync(configPath)) {
// eslint-disable-next-line import/no-dynamic-require
return require(configPath);
Expand All @@ -52,7 +60,28 @@ class BuildConfigManager {
// eslint-disable-next-line import/no-dynamic-require
return require(configPath);
}
return {};

// Fallback to cornerstone default stencil.conf.cjs
const content = await this.downloadFileFromGitHub(cornerstoneConfigLink);
this._fs.writeFileSync(configPath, content);

// eslint-disable-next-line import/no-dynamic-require
return require(configPath);
}

async downloadFileFromGitHub(rawUrl) {
try {
const response = await fetch(rawUrl);

if (!response.ok) {
console.log(`Failed to fetch file from ${rawUrl}: ${response.statusText}`);
}

return response.text();
} catch (error) {
console.error('Failed to fetch stencil.conf.cjs:', error);
return null;
}
}

_moveOldConfig(newPath, oldPath) {
Expand Down
26 changes: 25 additions & 1 deletion lib/BuildConfigManager.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from 'fs/promises';
import { jest } from '@jest/globals';
import { promisify } from 'util';
import BuildConfigManager from './BuildConfigManager.js';
Expand All @@ -8,10 +9,11 @@ describe('BuildConfigManager integration tests', () => {
jest.restoreAllMocks();
});
describe('constructor', () => {
it('should return an instance with correct watchOptions taken from the config file', () => {
it('should return an instance with correct watchOptions taken from the config file', async () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
});
await buildConfig.initConfig();
expect(buildConfig.watchOptions).toBeInstanceOf(Object);
expect(buildConfig.watchOptions.files).toBeInstanceOf(Array);
expect(buildConfig.watchOptions.ignored).toBeInstanceOf(Array);
Expand All @@ -22,6 +24,7 @@ describe('BuildConfigManager integration tests', () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
});
await buildConfig.initConfig();
buildConfig.initWorker();
expect(buildConfig.production).toBeInstanceOf(Function);
await promisify(buildConfig.production.bind(buildConfig))();
Expand All @@ -31,6 +34,7 @@ describe('BuildConfigManager integration tests', () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/legacy-config`,
});
await buildConfig.initConfig();
buildConfig.initWorker();
expect(buildConfig.production).toBeInstanceOf(Function);
await promisify(buildConfig.production.bind(buildConfig))();
Expand All @@ -40,19 +44,38 @@ describe('BuildConfigManager integration tests', () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/noworker-config`,
});
await buildConfig.initConfig();
const initedBuildConfig = buildConfig.initWorker();
expect(buildConfig.production).toBeInstanceOf(Function);
await expect(
promisify(initedBuildConfig.production.bind(initedBuildConfig))(),
).rejects.toContain('worker terminated');
buildConfig.stopWorker();
});
it('should download config from cornerstone github', async () => {
const workDir = `${cwd}/test/_mocks/build-config/no-config`;
const buildConfig = new BuildConfigManager({
workDir,
});
try {
await fs.access(workDir);
} catch (e) {
await fs.mkdir(workDir, { recursive: true });
}
await buildConfig.initConfig();
buildConfig.initWorker();
expect(buildConfig.production).toBeInstanceOf(Function);
await promisify(buildConfig.production.bind(buildConfig))();
buildConfig.stopWorker();
await fs.rm(`${cwd}/test/_mocks/build-config/no-config/stencil.conf.cjs`);
});
});
describe('development method', () => {
it('should reload the browser when a message "reload" is received from stencil.conf.js (valid-config)', async () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/valid-config`,
});
await buildConfig.initConfig();
expect(buildConfig.development).toBeInstanceOf(Function);
await new Promise((done) => buildConfig.initWorker().development({ reload: done }));
buildConfig.stopWorker();
Expand All @@ -61,6 +84,7 @@ describe('BuildConfigManager integration tests', () => {
const buildConfig = new BuildConfigManager({
workDir: `${cwd}/test/_mocks/build-config/legacy-config`,
});
await buildConfig.initConfig();
expect(buildConfig.development).toBeInstanceOf(Function);
await new Promise((done) => buildConfig.initWorker().development({ reload: done }));
buildConfig.stopWorker();
Expand Down
3 changes: 2 additions & 1 deletion lib/stencil-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ class Bundle {
tasks.schema = this.assembleSchema.bind(this);
tasks.schemaTranslations = this.assembleSchemaTranslations.bind(this);
if (typeof buildConfigManager.production === 'function') {
tasks.theme = (callback) => {
tasks.theme = async (callback) => {
console.log('Theme task Started...');
await buildConfigManager.initConfig();
buildConfigManager.initWorker().production((err) => {
if (err) {
return callback(err);
Expand Down
1 change: 1 addition & 0 deletions lib/stencil-start.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class StencilStart {
}
});
if (this._buildConfigManager.development) {
await this._buildConfigManager.initConfig();
this._buildConfigManager.initWorker().development(this._browserSync);
}
await this.checkLangFiles(langsPath, this._storeSettingsLocale.default_shopper_language);
Expand Down