diff --git a/package-lock.json b/package-lock.json index 2fe5391c..4fca3e15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.2", + "version": "5.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@gofynd/fdk-cli", - "version": "5.1.2", + "version": "5.2.0", "license": "MIT", "dependencies": { "@babel/core": "7.14.3", diff --git a/package.json b/package.json index dcb6105c..4c795ad9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.2", + "version": "5.2.0", "main": "index.js", "license": "MIT", "bin": { diff --git a/sample-upload.jpeg b/sample-upload.jpeg new file mode 100644 index 00000000..e2997fa2 --- /dev/null +++ b/sample-upload.jpeg @@ -0,0 +1,2 @@ +// ! DO NOT REMOVE +// This file is used to get CDN base path \ No newline at end of file diff --git a/sample-upload.js b/sample-upload.js new file mode 100644 index 00000000..e2997fa2 --- /dev/null +++ b/sample-upload.js @@ -0,0 +1,2 @@ +// ! DO NOT REMOVE +// This file is used to get CDN base path \ No newline at end of file diff --git a/src/__tests__/auth.spec.ts b/src/__tests__/auth.spec.ts index 735113b2..91a8b664 100644 --- a/src/__tests__/auth.spec.ts +++ b/src/__tests__/auth.spec.ts @@ -52,7 +52,6 @@ describe('Auth Commands', () => { setEnv(); program = await init('fdk'); const mock = new MockAdapter(axios); - mock.onGet(`${URLS.IS_VERSION_COMPATIBLE()}`).reply(200); await login(); }); diff --git a/src/__tests__/theme.spec.ts b/src/__tests__/theme.spec.ts index ecc0483a..c09c0732 100644 --- a/src/__tests__/theme.spec.ts +++ b/src/__tests__/theme.spec.ts @@ -137,7 +137,6 @@ describe('Theme Commands', () => { const mockInstance = new MockAdapter( uninterceptedApiClient.axiosInstance, ); - mock.onGet(`${URLS.IS_VERSION_COMPATIBLE()}`).reply(200); mock.onGet( `${URLS.GET_APPLICATION_DETAILS( appConfig.company_id, diff --git a/src/__tests__/themeContext.spec.ts b/src/__tests__/themeContext.spec.ts index 0202d59c..76f6e939 100644 --- a/src/__tests__/themeContext.spec.ts +++ b/src/__tests__/themeContext.spec.ts @@ -61,7 +61,6 @@ describe('Theme Context Commands', () => { setEnv(); program = await init('fdk'); const mock = new MockAdapter(axios); - mock.onGet(`${URLS.IS_VERSION_COMPATIBLE()}`).reply(200); mock.onGet( `${URLS.GET_APPLICATION_DETAILS( appConfig.company_id, diff --git a/src/helper/build.ts b/src/helper/build.ts index b2cc69dc..ebba2f09 100755 --- a/src/helper/build.ts +++ b/src/helper/build.ts @@ -6,9 +6,32 @@ import webpack, { MultiStats } from 'webpack'; import createBaseWebpackConfig from '../helper/theme.react.config'; import fs from 'fs'; import rimraf from 'rimraf'; +import Logger from '../lib/Logger'; export const THEME_ENTRY_FILE = path.join('theme', 'index.js'); +export const VUE_THEME_ENTRY_FILE = path.join("..",'theme', 'index.js'); +export const DEV_VUE_THEME_ENTRY_FILE = path.join('theme', 'index.js'); +export const CDN_ENTRY_FILE = path.join('.fdk', 'cdn_index.js'); + +export const dynamicCDNScript = ({assetNormalizedBasePath,vueJs }) => { + return `function getCDNurl() { + \n let cdnUrl; + \n try{ + \n if(fynd_platform_cdn) { + \n cdnUrl = fynd_platform_cdn + \n } else { + \n throw new Error("undefiend variable")} + \n } catch(error){ + \n cdnUrl = '${assetNormalizedBasePath}'} + \n return cdnUrl; + \n } + \n __webpack_public_path__ = getCDNurl() ${vueJs ? `\n + import bundle from "../theme/index.js"; + \n export default bundle; + ` + : ''}` +} export function build({ buildFolder, imageCdnUrl, @@ -23,13 +46,23 @@ export function build({ 'bin', 'vue-cli-service.js', ); + fs.stat(CDN_ENTRY_FILE, function (err, stat) { + if (err == null) { + //deleting file if exist + fs.unlink(CDN_ENTRY_FILE, function (err) { + if (err) return console.log(err); + Logger.debug(' \n Existing file deleted successfully'); + }); + } + fs.appendFileSync(CDN_ENTRY_FILE, dynamicCDNScript({ assetNormalizedBasePath:(imageCdnUrl|| assetCdnUrl),vueJs: true })); + }); const spinner = new Spinner('Building assets using vue-cli-service'); return new Promise((resolve, reject) => { spinner.start(); const isNodeVersionIsGreaterThan18 = +process.version.split('.')[0].slice(1) >= 18; let b = exec( - `node ${VUE_CLI_PATH} build --target lib --dest ${buildFolder} --name themeBundle --filename ${assetHash}_themeBundle ${THEME_ENTRY_FILE}`, + `node ${VUE_CLI_PATH} build --target lib --dest ${buildFolder} --name themeBundle --filename ${assetHash}_themeBundle ${CDN_ENTRY_FILE}`, { cwd: process.cwd(), env: { @@ -53,6 +86,10 @@ export function build({ b.stdout.pipe(process.stdout); b.stderr.pipe(process.stderr); b.on('exit', function (code) { + fs.unlink(CDN_ENTRY_FILE, function (err) { + if (err) return console.log(err); + Logger.debug(' \n Existing file deleted successfully'); + }); if (!code) { spinner.succeed(); return resolve(true); @@ -75,6 +112,7 @@ interface DevReactBuild { imageCdnUrl?: string; localThemePort?: string; isHMREnabled: boolean; + targetDirectory?:string } export function devBuild({ buildFolder, imageCdnUrl, isProd }: DevBuild) { @@ -91,7 +129,7 @@ export function devBuild({ buildFolder, imageCdnUrl, isProd }: DevBuild) { return new Promise((resolve, reject) => { let b = exec( - `node ${VUE_CLI_PATH} build --target lib --dest ${buildFolder} --name themeBundle ${THEME_ENTRY_FILE}`, + `node ${VUE_CLI_PATH} build --target lib --dest ${buildFolder} --name themeBundle ${DEV_VUE_THEME_ENTRY_FILE}`, { cwd: process.cwd(), env: { @@ -125,10 +163,11 @@ export function devBuild({ buildFolder, imageCdnUrl, isProd }: DevBuild) { export async function devReactBuild({ buildFolder, runOnLocal, - assetBasePath, + assetBasePath = '', localThemePort, imageCdnUrl, isHMREnabled, + targetDirectory }: DevReactBuild): Promise { const buildPath = path.join(process.cwd(), buildFolder); try { @@ -145,7 +184,6 @@ export async function devReactBuild({ themeWebpackConfigPath )); } - const ctx = { buildPath: buildPath, NODE_ENV: (!runOnLocal && 'production') || 'development', @@ -154,15 +192,39 @@ export async function devReactBuild({ localThemePort: localThemePort, context: process.cwd(), isHMREnabled, + targetDirectory }; const baseWebpackConfig = createBaseWebpackConfig( ctx, webpackConfigFromTheme, ); + const assetNormalizedBasePath = + assetBasePath[assetBasePath.length - 1] === '/' + ? assetBasePath + : assetBasePath + '/'; return new Promise((resolve, reject) => { + if(!runOnLocal) { + fs.stat(path.resolve((targetDirectory || process.cwd()), CDN_ENTRY_FILE), function (err, stat) { + if (err == null) { + //deleting file if exist + fs.unlink(path.resolve((targetDirectory || process.cwd()), CDN_ENTRY_FILE), function (err) { + if (err) return console.log(err); + Logger.debug(' \n Existing file deleted successfully'); + }); + } + fs.appendFileSync(path.resolve((targetDirectory || process.cwd()), CDN_ENTRY_FILE), dynamicCDNScript({assetNormalizedBasePath, vueJs: false })); + + }); + } webpack(baseWebpackConfig, (err, stats) => { console.log(err); console.log(stats.toString()); + if(!runOnLocal) { + fs.unlink(path.resolve((targetDirectory || process.cwd()), CDN_ENTRY_FILE), function (err) { + if (err) return console.log(err); + Logger.debug(' \n file deleted successfully'); + }); + } if (err || stats.hasErrors()) { reject(); } diff --git a/src/helper/serve.utils.ts b/src/helper/serve.utils.ts index 94c80541..728e79c0 100644 --- a/src/helper/serve.utils.ts +++ b/src/helper/serve.utils.ts @@ -218,7 +218,7 @@ export async function startServer({ domain, host, isSSR, port }) { 'fdk-cli-dev-files', User.current_user._id, ) - ).start.cdn.url; + ).complete.cdn.url; } else { jetfireUrl.searchParams.set('__csr', 'true'); } diff --git a/src/helper/theme.react.config.ts b/src/helper/theme.react.config.ts index 060b44fc..c2dfdb26 100644 --- a/src/helper/theme.react.config.ts +++ b/src/helper/theme.react.config.ts @@ -1,8 +1,11 @@ +import path from "path" import TerserPlugin from 'terser-webpack-plugin'; import webpack, { Configuration } from 'webpack'; import { mergeWithRules, merge } from 'webpack-merge'; import { getLocalBaseUrl } from './serve.utils'; const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); +import { CDN_ENTRY_FILE } from './build'; +const context = process.cwd(); const baseConfig = (configOptions) => { const { @@ -15,7 +18,6 @@ const baseConfig = (configOptions) => { return { mode: isLocal ? 'development' : 'production', - devtool: isLocal ? 'source-map' : false, optimization: { minimizer: [ @@ -83,6 +85,7 @@ export default (ctx, extendedWebpackConfig): Configuration[] => { imageCdnUrl = '', localThemePort = 5500, isHMREnabled = true, + targetDirectory } = ctx; const assetNormalizedBasePath = @@ -109,7 +112,6 @@ export default (ctx, extendedWebpackConfig): Configuration[] => { }; const baseWebpackConfig = baseConfig(configOptions); const extendedWebpackResolved = extendedWebpackConfig(configOptions); - const mergedBaseConfig: Configuration = mergeWithRules({ module: { rules: { @@ -120,14 +122,14 @@ export default (ctx, extendedWebpackConfig): Configuration[] => { })(extendedWebpackResolved, baseWebpackConfig); if (mergedBaseConfig.entry.hasOwnProperty('themeBundle')) { - mergedBaseConfig.entry['themeBundle'] = - isLocal && isHMREnabled - ? [ - require.resolve('webpack-hot-middleware/client'), - ...mergedBaseConfig.entry['themeBundle'], - ] - : mergedBaseConfig.entry['themeBundle']; + let entryPoints = [...mergedBaseConfig.entry['themeBundle']]; + if (isLocal && isHMREnabled) { + entryPoints.unshift(require.resolve('webpack-hot-middleware/client')); + } else if (!isLocal) { + entryPoints.unshift(path.resolve(targetDirectory || context, CDN_ENTRY_FILE)); + } + mergedBaseConfig.entry['themeBundle'] = entryPoints; } - + return [mergedBaseConfig]; }; diff --git a/src/lib/Auth.ts b/src/lib/Auth.ts index 1ebd23b0..e1a17e1c 100644 --- a/src/lib/Auth.ts +++ b/src/lib/Auth.ts @@ -61,16 +61,11 @@ export const startServer = async () => { return Auth.server; }; -async function checkVersionCompatibility() { - const response = await ThemeService.checkCompatibleVersion(); -} - export default class Auth { static server = null; static isOrganizationChange = false; constructor() {} public static async login() { - await checkVersionCompatibility(); Logger.info( chalk.green( 'Current env: ', diff --git a/src/lib/CommandError.ts b/src/lib/CommandError.ts index 53288228..dcd59a59 100644 --- a/src/lib/CommandError.ts +++ b/src/lib/CommandError.ts @@ -53,11 +53,6 @@ export const ErrorCodes = { `No themes are created, Please create/add a theme under the sales channel. For more details, refer to the documentation link: ${domain}/help/docs/partners/themes/vuejs/overview`, code: 'FDK-00011', }, - DOWNGRADE_CLI_VERSION: { - message: - 'Seems like current Fynd Platform version is not compatible with installed CLI version.\n\nIn order to continue with current FP version, Please use previous version of CLI `npm install -g @gofynd/fdk-cli@3.0.4` command.', - code: 'FDK-00012', - }, // generic ECONN_RESET: { diff --git a/src/lib/Theme.ts b/src/lib/Theme.ts index 9434f171..5f5700a4 100644 --- a/src/lib/Theme.ts +++ b/src/lib/Theme.ts @@ -35,7 +35,7 @@ import ThemeService from './api/services/theme.service'; import UploadService from './api/services/upload.service'; import ExtensionService from './api/services/extension.service'; import { - THEME_ENTRY_FILE, + DEV_VUE_THEME_ENTRY_FILE, build, devBuild, devReactBuild, @@ -114,10 +114,8 @@ export default class Theme { public static async getThemeBundle(stats: MultiStats) { const fileList = stats.stats[0].toJson().assets.map(({ name }) => name); const outputFileName= fileList.find(file => file.startsWith('themeBundle') && file.endsWith('.js')); - const buildPath = path.join(process.cwd(), Theme.BUILD_FOLDER); const outputFilePath = path.resolve(buildPath, outputFileName); - const bundle = Theme.evaluateBundle(outputFilePath); const parsed = await bundle({ @@ -350,6 +348,10 @@ export default class Theme { }); config['application_id'] = selectedApplication; config['company_id'] = selectedCompany; + // config['application_id'] = "6672cdcc9399006687477a5c"; + // config['company_id'] = 63; + console.log({config}); + return config; } @@ -610,7 +612,7 @@ export default class Theme { spaces: 2, }); const currentContext = getActiveContext(); - await Theme.syncReactTheme(currentContext); + await Theme.syncReactTheme(currentContext, targetDirectory); var b5 = Box( chalk.green.bold('DONE ') + chalk.green.bold('Project ready\n') + @@ -791,10 +793,7 @@ export default class Theme { spaces: 2, }, ); - if ( - !fs.existsSync(path.join(process.cwd(), THEME_ENTRY_FILE)) && - themeData.theme_type === THEME_TYPE.vue2 - ) { + if (!fs.existsSync(path.join(process.cwd(), DEV_VUE_THEME_ENTRY_FILE)) && (themeData.theme_type === THEME_TYPE.vue2)) { Logger.info('Restructuring folder structure'); let restructureSpinner = new Spinner( 'Restructuring folder structure', @@ -822,7 +821,7 @@ export default class Theme { const currentContext = getActiveContext(); switch (currentContext.theme_type) { case THEME_TYPE.react: - await Theme.syncReactTheme(currentContext); + await Theme.syncReactTheme(currentContext, undefined); break; case THEME_TYPE.vue2: await Theme.syncVueTheme(currentContext); @@ -834,6 +833,7 @@ export default class Theme { }; private static syncReactTheme = async ( currentContext: ThemeContextInterface, + targetDirectory ) => { try { await Theme.ensureThemeTypeInPackageJson(); @@ -877,6 +877,7 @@ export default class Theme { assetBasePath, imageCdnUrl, isHMREnabled: false, + targetDirectory }); const parsed = await Theme.getThemeBundle(stats); @@ -1680,20 +1681,22 @@ export default class Theme { }; private static getImageCdnBaseUrl = async () => { - let imageCdnUrl = ''; try { - let startData = { - file_name: 'test.jpg', - content_type: 'image/jpeg', - size: '1', - }; - let startAssetData = ( - await UploadService.startUpload( - startData, - 'application-theme-images', - ) - ).data; - return (imageCdnUrl = path.dirname(startAssetData.cdn.url)); + const dummyFile = path.join( + __dirname, + '..', + '..', + 'sample-upload.jpeg' + ); + + const response = await UploadService.uploadFile( + dummyFile, + 'application-theme-images', + null, + 'image/jpeg' + ); + + return path.dirname(response.complete.cdn.url); } catch (err) { Logger.error(err); throw new CommandError( @@ -1704,20 +1707,23 @@ export default class Theme { }; private static getAssetCdnBaseUrl = async () => { - let assetCdnUrl = ''; try { - const startData = { - file_name: 'test.ttf', - content_type: 'font/ttf', - size: '10', - }; - const startAssetData = ( - await UploadService.startUpload( - startData, - 'application-theme-assets', - ) - ).data; - return (assetCdnUrl = path.dirname(startAssetData.cdn.url)); + const dummyFile = path.join( + __dirname, + '..', + '..', + 'sample-upload.js' + ); + + const response = await UploadService.uploadFile( + dummyFile, + 'application-theme-assets', + null, + 'application/javascript' + ); + + return path.dirname(response.complete.cdn.url); + } catch (err) { throw new CommandError( `Failed in getting assets CDN base url`, @@ -1884,7 +1890,7 @@ export default class Theme { path.join(process.cwd(), Theme.BUILD_FOLDER, commonJS), 'application-theme-assets', ); - const commonJsUrl = commonJsUrlRes.start.cdn.url; + const commonJsUrl = commonJsUrlRes.complete.cdn.url; Logger.info('Uploading umdJS'); const umdMinAssets = glob.sync( @@ -1921,9 +1927,9 @@ export default class Theme { }); const cssUrls = await Promise.all(cssPromisesArr); return [ - cssUrls.map((res) => res.start.cdn.url), + cssUrls.map((res) => res.complete.cdn.url), commonJsUrl, - umdJsUrls.map((res) => res.start.cdn.url), + umdJsUrls.map((res) => res.complete.cdn.url), ]; } catch (err) { throw new CommandError( @@ -2528,7 +2534,7 @@ export default class Theme { zipFilePath, 'application-theme-src', ); - return res.start.cdn.url; + return res.complete.cdn.url; } catch (err) { throw new CommandError( err.message || `Failed to upload src folder`, diff --git a/src/lib/api/helper/interceptors.ts b/src/lib/api/helper/interceptors.ts index 95d86cd9..e536977b 100644 --- a/src/lib/api/helper/interceptors.ts +++ b/src/lib/api/helper/interceptors.ts @@ -129,15 +129,6 @@ export function responseErrorInterceptor() { ) { ConfigStore.delete(CONFIG_KEYS.AUTH_TOKEN); throw new CommandError(COMMON_LOG_MESSAGES.RequireAuth); - } else if ( - error.response && - error.response.status === 404 && - error.response.config.url.includes('/_compatibility') - ) { - throw new CommandError( - ErrorCodes.DOWNGRADE_CLI_VERSION.message, - ErrorCodes.DOWNGRADE_CLI_VERSION.code, - ); } else if (error.response) { Debug(`Error Response : ${JSON.stringify(error.response.data)}`); throw new CommandError( diff --git a/src/lib/api/services/theme.service.ts b/src/lib/api/services/theme.service.ts index 74fd27ed..560a2551 100644 --- a/src/lib/api/services/theme.service.ts +++ b/src/lib/api/services/theme.service.ts @@ -227,18 +227,6 @@ export default { throw error; } }, - checkCompatibleVersion: async () => { - try { - let axiosOptions = Object.assign({}, getCommonHeaderOptions()); - let response = await ApiClient.get( - URLS.IS_VERSION_COMPATIBLE(), - axiosOptions, - ); - return response.data; - } catch (error) { - throw error; - } - }, getDefaultTheme: async (data) => { try { const axiosOption = Object.assign({}, getCommonHeaderOptions()); diff --git a/src/lib/api/services/upload.service.ts b/src/lib/api/services/upload.service.ts index 9f0ba2d3..929f8b71 100644 --- a/src/lib/api/services/upload.service.ts +++ b/src/lib/api/services/upload.service.ts @@ -8,25 +8,8 @@ import mime from 'mime'; import Spinner from '../../../helper/spinner'; export default { - startUpload: async (data, namespace) => { - try { - const axiosOption = Object.assign( - {}, - { - data: data, - }, - getCommonHeaderOptions(), - ); - const res = await ApiClient.post( - URLS.START_UPLOAD_FILE(namespace), - axiosOption, - ); - return res; - } catch (error) { - throw error; - } - }, - uploadFile: async (filepath, namespace, file_name = null) => { + + uploadFile: async (filepath, namespace, file_name = null, mimeType = null) => { let spinner = new Spinner(); let textMessage; try { @@ -35,7 +18,8 @@ export default { filepath, )} [${Math.round(stats.size / 1024)} KB]`; spinner.start(textMessage); - let contentType = mime.getType(path.extname(filepath)); + let contentType = mimeType || mime.getType(path.extname(filepath)); + if (contentType === 'image/jpg') { contentType = 'image/jpeg'; } diff --git a/src/lib/api/services/url.ts b/src/lib/api/services/url.ts index be4de5cf..ebbe7ebd 100644 --- a/src/lib/api/services/url.ts +++ b/src/lib/api/services/url.ts @@ -178,8 +178,4 @@ export const URLS = { `/organization/${organization_id}/accounts/access-request?page_size=${page_size}&page_no=${page_no}&request_status=accepted`, ); }, - - IS_VERSION_COMPATIBLE: () => { - return urlJoin(BLITZKRIEG_PANEL_URL(), '/_compatibility'); - }, };