mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Migrated Portal from CRA to Vite
refs https://github.com/TryGhost/Ghost/issues/15502 - this commit migrates Portal from CRA to Vite, as it brings the package more inline with the direction we're going in terms of tooling for builds - the bulk of the changes here are just config related to get things working with Vite, and then cleaning up all the CRA boilerplate
This commit is contained in:
parent
cdcb3dcd6f
commit
327fef0ad8
17 changed files with 1143 additions and 3255 deletions
|
@ -7,7 +7,6 @@
|
|||
"url": "git://github.com/TryGhost/Ghost.git"
|
||||
},
|
||||
"author": "Ghost Foundation",
|
||||
"unpkg": "umd/portal.min.js",
|
||||
"files": [
|
||||
"umd/",
|
||||
"LICENSE",
|
||||
|
@ -17,35 +16,18 @@
|
|||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/react": "7.42.0",
|
||||
"@sentry/tracing": "7.42.0",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@tryghost/i18n": "0.0.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-scripts": "5.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "BROWSER=none react-scripts start",
|
||||
"start:combined": "BROWSER=none node ./scripts/start-combined.js",
|
||||
"start:dev": "node ./scripts/start-mode.js",
|
||||
"dev": "node ./scripts/dev-mode.js",
|
||||
"build": "npm run build:combined",
|
||||
"build:original": "react-scripts build",
|
||||
"build:combined": "node ./scripts/build-combined.js",
|
||||
"test": "react-scripts test",
|
||||
"test:ci": "yarn test --watchAll=false --coverage",
|
||||
"dev": "concurrently \"vite\" \"yarn build:watch\"",
|
||||
"build": "vite build",
|
||||
"build:watch": "vite build --watch",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest run",
|
||||
"test:ci": "yarn test --coverage",
|
||||
"test:unit": "yarn test:ci",
|
||||
"eject": "react-scripts eject",
|
||||
"lint": "eslint src --ext .js --cache",
|
||||
"preship": "yarn lint",
|
||||
"ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then yarn version; fi",
|
||||
"postship": "git push ${GHOST_UPSTREAM:-origin} --follow-tags && yarn publish . --tag $npm_package_version",
|
||||
"posttest": "yarn lint",
|
||||
"analyze": "source-map-explorer 'umd/*.js'",
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -55,10 +37,7 @@
|
|||
],
|
||||
"plugins": [
|
||||
"ghost"
|
||||
],
|
||||
"rules": {
|
||||
"import/no-webpack-loader-syntax": "off"
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
@ -77,24 +56,28 @@
|
|||
"cobertura",
|
||||
"text-summary",
|
||||
"html"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^!!raw-loader!.*": "jest-raw-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"chokidar": "3.5.3",
|
||||
"jest-raw-loader": "1.0.1",
|
||||
"minimist": "1.2.8",
|
||||
"ora": "5.4.1",
|
||||
"raw-loader": "4.0.2",
|
||||
"rewire": "6.0.0",
|
||||
"serve-handler": "6.1.5",
|
||||
"source-map-explorer": "2.5.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"//": "See https://github.com/facebook/create-react-app/issues/11773",
|
||||
"react-error-overlay": "6.0.11"
|
||||
"@babel/eslint-parser": "7.21.3",
|
||||
"@sentry/react": "7.42.0",
|
||||
"@sentry/tracing": "7.42.0",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@tryghost/i18n": "0.0.0",
|
||||
"@vitejs/plugin-react": "3.1.0",
|
||||
"@vitest/coverage-c8": "0.29.3",
|
||||
"@vitest/ui": "0.29.3",
|
||||
"concurrently": "7.6.0",
|
||||
"cross-fetch": "3.1.5",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-react-app": "7.0.1",
|
||||
"jsdom": "21.1.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"vite": "4.1.4",
|
||||
"vite-plugin-css-injected-by-js": "3.1.0",
|
||||
"vite-plugin-svgr": "2.4.0",
|
||||
"vitest": "0.29.2"
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
|
@ -1,43 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.4 KiB |
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
|
@ -1,29 +0,0 @@
|
|||
const rewire = require('rewire');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const defaults = rewire('react-scripts/scripts/build.js');
|
||||
let config = defaults.__get__('config');
|
||||
|
||||
config.optimization.splitChunks = {
|
||||
cacheGroups: {
|
||||
default: false
|
||||
}
|
||||
};
|
||||
|
||||
config.optimization.runtimeChunk = false;
|
||||
|
||||
// JS: Save built file in `/umd`
|
||||
config.output.filename = '../umd/portal.min.js';
|
||||
|
||||
// CSS: Remove MiniCssPlugin from list of plugins
|
||||
config.plugins = config.plugins.filter(plugin => !(plugin instanceof MiniCssExtractPlugin));
|
||||
// CSS: replaces all MiniCssExtractPlugin.loader with style-loader to embed CSS in JS
|
||||
config.module.rules[1].oneOf = config.module.rules[1].oneOf.map((rule) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(rule, 'use')) {
|
||||
return rule;
|
||||
}
|
||||
return Object.assign({}, rule, {
|
||||
use: rule.use.map(options => (/mini-css-extract-plugin/.test(options.loader)
|
||||
? {loader: require.resolve('style-loader'), options: {}}
|
||||
: options))
|
||||
});
|
||||
});
|
|
@ -1,200 +0,0 @@
|
|||
const handler = require('serve-handler');
|
||||
const http = require('http');
|
||||
const chokidar = require('chokidar');
|
||||
const chalk = require('chalk');
|
||||
const {spawn} = require('child_process');
|
||||
const minimist = require('minimist');
|
||||
const ora = require('ora');
|
||||
|
||||
/* eslint-disable no-console */
|
||||
const log = console.log;
|
||||
/* eslint-enable no-console */
|
||||
|
||||
let buildProcess;
|
||||
let fileChanges = [];
|
||||
let spinner;
|
||||
let stdOutChunks = [];
|
||||
let stdErrChunks = [];
|
||||
|
||||
const {v, verbose, port = 5368, basic, b} = minimist(process.argv.slice(2));
|
||||
const showVerbose = !!(v || verbose);
|
||||
const showBasic = !!(b || basic);
|
||||
|
||||
function maybePluralize(count, noun, suffix = 's') {
|
||||
return `${count} ${noun}${count !== 1 ? suffix : ''}`;
|
||||
}
|
||||
|
||||
function printFileChanges() {
|
||||
if (fileChanges.length > 0) {
|
||||
const prefix = maybePluralize(fileChanges.length, 'file');
|
||||
log(chalk.bold.hex('#ffa300').underline(`${prefix} changed`));
|
||||
const message = fileChanges.map((path) => {
|
||||
return chalk.hex('#ffa300').dim(`${path}`);
|
||||
}).join('\n');
|
||||
log(message);
|
||||
log();
|
||||
}
|
||||
}
|
||||
|
||||
function printBuildSuccessDetails() {
|
||||
if (showBasic) {
|
||||
return;
|
||||
}
|
||||
if ((stdOutChunks && stdOutChunks.length > 0)) {
|
||||
const detail = Buffer.concat(stdOutChunks.slice(4,7)).toString();
|
||||
log();
|
||||
log(chalk.dim(detail));
|
||||
}
|
||||
}
|
||||
|
||||
function printBuildErrorDetails() {
|
||||
if ((stdOutChunks && stdOutChunks.length > 0)) {
|
||||
const failDetails = Buffer.concat(stdOutChunks.slice(4, stdOutChunks.length - 1)).toString().replace(/^(?=\n)$|\s*$|\n\n+/gm, '');
|
||||
log(chalk(failDetails));
|
||||
}
|
||||
if (stdErrChunks && stdErrChunks.length > 0) {
|
||||
const stderrContent = Buffer.concat(stdErrChunks).toString();
|
||||
log(chalk.dim(stderrContent));
|
||||
}
|
||||
}
|
||||
|
||||
function printBuildComplete(code) {
|
||||
if (code === 0) {
|
||||
if (!showVerbose) {
|
||||
spinner && spinner.succeed(chalk.greenBright.bold('Build finished'));
|
||||
printBuildSuccessDetails();
|
||||
} else {
|
||||
log();
|
||||
log(chalk.bold.greenBright.bgBlackBright(`${'-'.repeat(25)}Build Success${'-'.repeat(25)}`));
|
||||
}
|
||||
} else {
|
||||
if (!showVerbose) {
|
||||
spinner && spinner.fail(chalk.redBright.bold('Build failed'));
|
||||
printBuildErrorDetails();
|
||||
} else {
|
||||
log(chalk.bold.redBright.bgBlackBright(`${'-'.repeat(25)}Build finished: Failed${'-'.repeat(25)}`));
|
||||
}
|
||||
}
|
||||
log();
|
||||
}
|
||||
|
||||
function printConfigInstruction() {
|
||||
const data = {
|
||||
portal: {
|
||||
url: `http://localhost:${port}/portal`
|
||||
}
|
||||
};
|
||||
const stringifedData = JSON.stringify(data, null, 2);
|
||||
const splitData = stringifedData.split('\n');
|
||||
log();
|
||||
splitData.forEach((_data, idx, arr) => {
|
||||
if (idx === 0 || idx === arr.length - 1) {
|
||||
log(chalk.grey(_data));
|
||||
} else {
|
||||
log(chalk.bold.whiteBright(_data));
|
||||
}
|
||||
});
|
||||
log();
|
||||
}
|
||||
|
||||
function printBuildStart() {
|
||||
if (showVerbose) {
|
||||
log(chalk.bold.greenBright.bgBlackBright(`${'-'.repeat(32)}Building${'-'.repeat(32)}`));
|
||||
log();
|
||||
} else {
|
||||
spinner = ora(chalk.magentaBright.bold('Bundling files, hang on...')).start();
|
||||
}
|
||||
}
|
||||
|
||||
function onBuildComplete(code) {
|
||||
buildProcess = null;
|
||||
printBuildComplete(code);
|
||||
stdErrChunks = [];
|
||||
stdOutChunks = [];
|
||||
if (fileChanges.length > 0) {
|
||||
buildPortal();
|
||||
} else {
|
||||
log(chalk.yellowBright.bold.underline(`Watching file changes...\n`));
|
||||
}
|
||||
}
|
||||
|
||||
function getBuildOptions() {
|
||||
process.env.FORCE_COLOR = 'true';
|
||||
const options = {
|
||||
shell: true,
|
||||
env: process.env
|
||||
};
|
||||
if (showVerbose) {
|
||||
options.stdio = 'inherit';
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function buildPortal() {
|
||||
if (buildProcess) {
|
||||
return;
|
||||
}
|
||||
printFileChanges();
|
||||
printBuildStart();
|
||||
fileChanges = [];
|
||||
const options = getBuildOptions();
|
||||
buildProcess = spawn('yarn build', options);
|
||||
|
||||
buildProcess.on('close', onBuildComplete);
|
||||
|
||||
if (!showVerbose) {
|
||||
buildProcess.stdout.on('data', (data) => {
|
||||
stdOutChunks.push(data);
|
||||
});
|
||||
buildProcess.stderr.on('data', (data) => {
|
||||
stdErrChunks.push(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function watchFiles() {
|
||||
const watcher = chokidar.watch('.', {
|
||||
ignored: /build|node_modules|.git|public|umd|scripts|(^|[\/\\])\../
|
||||
});
|
||||
|
||||
watcher.on('ready', () => {
|
||||
buildPortal();
|
||||
}).on('change', (path) => {
|
||||
if (!fileChanges.includes(path)) {
|
||||
fileChanges.push(path);
|
||||
}
|
||||
if (!buildProcess) {
|
||||
buildPortal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function startDevServer() {
|
||||
const server = http.createServer((request, response) => {
|
||||
return handler(request, response, {
|
||||
rewrites: [
|
||||
{source: '/portal', destination: 'umd/portal.min.js'},
|
||||
{source: '/portal.min.js.map', destination: 'umd/portal.min.js.map'}
|
||||
],
|
||||
headers: [
|
||||
{
|
||||
source: '**',
|
||||
headers: [{
|
||||
key: 'Cache-Control',
|
||||
value: 'no-cache'
|
||||
},{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: '*'
|
||||
}]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(port, () => {
|
||||
log(chalk.whiteBright(`Portal dev server is running on http://localhost:${port}`));
|
||||
watchFiles();
|
||||
});
|
||||
}
|
||||
|
||||
startDevServer();
|
|
@ -1,8 +0,0 @@
|
|||
/** Script to load Portal bundle for local development */
|
||||
function loadScript(src) {
|
||||
var script = document.createElement('script');
|
||||
script.src = src;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
loadScript('http://localhost:3000/static/js/bundle.js');
|
|
@ -1,14 +0,0 @@
|
|||
const rewire = require('rewire');
|
||||
const defaults = rewire('react-scripts/scripts/start.js');
|
||||
let configFactory = defaults.__get__('configFactory');
|
||||
|
||||
defaults.__set__('configFactory', (env) => {
|
||||
const config = configFactory(env);
|
||||
config.optimization.splitChunks = {
|
||||
cacheGroups: {
|
||||
default: false
|
||||
}
|
||||
};
|
||||
config.optimization.runtimeChunk = false;
|
||||
return config;
|
||||
});
|
|
@ -1,151 +0,0 @@
|
|||
const handler = require('serve-handler');
|
||||
const http = require('http');
|
||||
const chalk = require('chalk');
|
||||
const {spawn} = require('child_process');
|
||||
const minimist = require('minimist');
|
||||
|
||||
/* eslint-disable no-console */
|
||||
const log = console.log;
|
||||
/* eslint-enable no-console */
|
||||
|
||||
let yarnStartProcess;
|
||||
let stdOutChunks = [];
|
||||
let stdErrChunks = [];
|
||||
let startYarnOutput = false;
|
||||
|
||||
const {v, verbose, port = 5368} = minimist(process.argv.slice(2));
|
||||
const showVerbose = !!(v || verbose);
|
||||
|
||||
function clearConsole({withHistory = true} = {}) {
|
||||
if (!withHistory) {
|
||||
process.stdout.write('\x1Bc');
|
||||
return;
|
||||
}
|
||||
process.stdout.write(
|
||||
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
|
||||
);
|
||||
}
|
||||
|
||||
function printConfigInstruction() {
|
||||
const data = {
|
||||
portal: {
|
||||
url: `http://localhost:${port}/portal`
|
||||
}
|
||||
};
|
||||
const stringifedData = JSON.stringify(data, null, 2);
|
||||
const splitData = stringifedData.split('\n');
|
||||
log();
|
||||
splitData.forEach((data, idx, arr) => {
|
||||
if (idx === 0 || idx === arr.length - 1) {
|
||||
log(chalk.grey(data));
|
||||
} else {
|
||||
log(chalk.bold.whiteBright(data));
|
||||
}
|
||||
});
|
||||
log();
|
||||
}
|
||||
|
||||
function printInstructions() {
|
||||
log();
|
||||
log(chalk.yellowBright.underline(`Add portal to your local Ghost config`));
|
||||
printConfigInstruction();
|
||||
log(chalk.cyanBright('='.repeat(50)));
|
||||
log();
|
||||
}
|
||||
|
||||
function onProcessClose(code) {
|
||||
yarnStartProcess = null;
|
||||
stdErrChunks = [];
|
||||
stdOutChunks = [];
|
||||
log(chalk.redBright.bold.underline(`Please restart the script...\n`));
|
||||
}
|
||||
|
||||
function getBuildOptions() {
|
||||
process.env.FORCE_COLOR = 'true';
|
||||
const options = {
|
||||
shell: true,
|
||||
env: process.env
|
||||
};
|
||||
if (showVerbose) {
|
||||
options.stdio = 'inherit';
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function doYarnStart() {
|
||||
if (yarnStartProcess) {
|
||||
return;
|
||||
}
|
||||
const options = getBuildOptions();
|
||||
yarnStartProcess = spawn('yarn start:combined', options);
|
||||
|
||||
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
||||
yarnStartProcess.on(sig, function () {
|
||||
yarnStartProcess && yarnStartProcess.exit();
|
||||
});
|
||||
});
|
||||
|
||||
yarnStartProcess.on('close', onProcessClose);
|
||||
|
||||
if (!showVerbose) {
|
||||
yarnStartProcess.stdout.on('data', (data) => {
|
||||
stdOutChunks.push(data);
|
||||
printYarnProcessOutput(data);
|
||||
});
|
||||
yarnStartProcess.stderr.on('data', (data) => {
|
||||
log(Buffer.from(data).toString());
|
||||
stdErrChunks.push(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function printYarnProcessOutput(data) {
|
||||
const dataStr = Buffer.from(data).toString();
|
||||
const dataArr = dataStr.split('\n').filter((d) => {
|
||||
return /\S/.test(d.trim());
|
||||
});
|
||||
if (dataArr.find(d => d.includes('Starting the development'))) {
|
||||
startYarnOutput = true;
|
||||
log(chalk.yellowBright('Starting the development server...\n'));
|
||||
return;
|
||||
}
|
||||
dataArr.forEach((dataOut) => {
|
||||
if (startYarnOutput) {
|
||||
log(dataOut);
|
||||
}
|
||||
});
|
||||
if (startYarnOutput) {
|
||||
log();
|
||||
}
|
||||
}
|
||||
|
||||
function startDevServer() {
|
||||
const server = http.createServer((request, response) => {
|
||||
return handler(request, response, {
|
||||
rewrites: [
|
||||
{source: '/portal', destination: 'scripts/load-portal.js'}
|
||||
],
|
||||
headers: [
|
||||
{
|
||||
source: '**',
|
||||
headers: [{
|
||||
key: 'Cache-Control',
|
||||
value: 'no-cache'
|
||||
},{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: '*'
|
||||
}]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(port, () => {
|
||||
log(chalk.whiteBright(`Portal dev server is running on http://localhost:${port}`));
|
||||
printInstructions();
|
||||
doYarnStart();
|
||||
});
|
||||
}
|
||||
|
||||
clearConsole({withHistory: false});
|
||||
startDevServer();
|
|
@ -14,6 +14,8 @@ import NotificationParser from './utils/notifications';
|
|||
import {allowCompMemberUpgrade, createPopupNotification, getCurrencySymbol, getFirstpromoterId, getPriceIdFromPageQuery, getProductCadenceFromPrice, getProductFromId, getQueryPrice, getSiteDomain, isActiveOffer, isComplimentaryMember, isInviteOnlySite, isPaidMember, isSentryEventAllowed, removePortalLinkFromUrl} from './utils/helpers';
|
||||
import {handleDataAttributes} from './data-attributes';
|
||||
|
||||
import i18nLib from '@tryghost/i18n';
|
||||
|
||||
const DEV_MODE_DATA = {
|
||||
showPopup: true,
|
||||
site: Fixtures.site,
|
||||
|
@ -155,7 +157,7 @@ export default class App extends React.Component {
|
|||
try {
|
||||
// Fetch data from API, links, preview, dev sources
|
||||
const {site, member, page, showPopup, popupNotification, lastPage, pageQuery, pageData} = await this.fetchData();
|
||||
const i18n = require('@tryghost/i18n')(/*site.locale || */ 'en', 'portal'); // TODO: uncomment when you want to enable i18n translations
|
||||
const i18n = i18nLib(/*site.locale || */ 'en', 'portal'); // TODO: uncomment when you want to enable i18n translations
|
||||
const state = {
|
||||
site,
|
||||
member,
|
||||
|
@ -507,7 +509,8 @@ export default class App extends React.Component {
|
|||
return null;
|
||||
}
|
||||
const {portal_sentry: portalSentry, portal_version: portalVersion, version: ghostVersion} = site;
|
||||
const appVersion = process.env.REACT_APP_VERSION || portalVersion;
|
||||
// eslint-disable-next-line no-undef
|
||||
const appVersion = REACT_APP_VERSION || portalVersion;
|
||||
const releaseTag = `portal@${appVersion}|ghost@${ghostVersion}`;
|
||||
if (portalSentry && portalSentry.dsn) {
|
||||
Sentry.init({
|
||||
|
|
|
@ -7,7 +7,7 @@ import {GlobalStyles} from './Global.styles';
|
|||
import {ActionButtonStyles} from './common/ActionButton';
|
||||
import {BackButtonStyles} from './common/BackButton';
|
||||
import {SwitchStyles} from './common/Switch';
|
||||
import AccountHomePageStyles from '!!raw-loader!./pages/AccountHomePage/AccountHomePage.css';
|
||||
import AccountHomePageStyles from './pages/AccountHomePage/AccountHomePage.css';
|
||||
import {AccountPlanPageStyles} from './pages/AccountPlanPage';
|
||||
import {InputFieldStyles} from './common/InputField';
|
||||
import {SignupPageStyles} from './pages/SignupPage';
|
||||
|
@ -17,9 +17,9 @@ import {MagicLinkStyles} from './pages/MagicLinkPage';
|
|||
import {PopupNotificationStyles} from './common/PopupNotification';
|
||||
import {OfferPageStyles} from './pages/OfferPage';
|
||||
import {FeedbackPageStyles} from './pages/FeedbackPage';
|
||||
import EmailSuppressedPage from '!!raw-loader!./pages/EmailSuppressedPage.css';
|
||||
import EmailSuppressionFAQ from '!!raw-loader!./pages/EmailSuppressionFAQ.css';
|
||||
import EmailReceivingFAQ from '!!raw-loader!./pages/EmailReceivingFAQ.css';
|
||||
import EmailSuppressedPage from './pages/EmailSuppressedPage.css';
|
||||
import EmailSuppressionFAQ from './pages/EmailSuppressionFAQ.css';
|
||||
import EmailReceivingFAQ from './pages/EmailReceivingFAQ.css';
|
||||
|
||||
// Global styles
|
||||
const FrameStyles = `
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
import {afterEach, expect} from 'vitest';
|
||||
import {cleanup} from '@testing-library/react';
|
||||
import {fetch} from 'cross-fetch';
|
||||
import matchers from '@testing-library/jest-dom/matchers';
|
||||
|
||||
// TODO: remove this once we're switched `jest` to `vi` in code
|
||||
// eslint-disable-next-line no-undef
|
||||
globalThis.jest = vi;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
globalThis.fetch = fetch;
|
||||
|
||||
// Add the cleanup function for React testing library
|
||||
afterEach(cleanup);
|
||||
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
expect.extend(matchers);
|
||||
|
|
80
ghost/portal/vite.config.js
Normal file
80
ghost/portal/vite.config.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
import {resolve} from 'path';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
import {defineConfig} from 'vitest/config';
|
||||
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
|
||||
import reactPlugin from '@vitejs/plugin-react';
|
||||
import svgrPlugin from 'vite-plugin-svgr';
|
||||
|
||||
import pkg from './package.json';
|
||||
|
||||
import {SUPPORTED_LOCALES} from '@tryghost/i18n';
|
||||
|
||||
export default defineConfig((config) => {
|
||||
const outputFileName = pkg.name[0] === '@' ? pkg.name.slice(pkg.name.indexOf('/') + 1) : pkg.name;
|
||||
|
||||
return {
|
||||
clearScreen: false,
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(config.mode),
|
||||
REACT_APP_VERSION: JSON.stringify(process.env.npm_package_version),
|
||||
},
|
||||
server: {
|
||||
port: 5368,
|
||||
},
|
||||
plugins: [
|
||||
cssInjectedByJsPlugin(),
|
||||
reactPlugin(),
|
||||
svgrPlugin(),
|
||||
],
|
||||
esbuild: {
|
||||
loader: "jsx",
|
||||
include: /src\/.*\.jsx?$/,
|
||||
exclude: [],
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
plugins: [
|
||||
{
|
||||
name: "load-js-files-as-jsx",
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /src\/.*\.js$/ }, async (args) => ({
|
||||
loader: "jsx",
|
||||
contents: await fs.readFile(args.path, "utf8"),
|
||||
}));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: resolve(__dirname, 'umd'),
|
||||
emptyOutDir: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
cssCodeSplit: false,
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/index.js'),
|
||||
formats: ['umd'],
|
||||
name: pkg.name,
|
||||
fileName: (format) => `${outputFileName}.min.js`,
|
||||
},
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: false,
|
||||
}
|
||||
},
|
||||
commonjsOptions: {
|
||||
include: [/ghost/, /node_modules/],
|
||||
dynamicRequireRoot: '../',
|
||||
dynamicRequireTargets: SUPPORTED_LOCALES.map((locale) => `../i18n/locales/${locale}/portal.json`),
|
||||
}
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: './src/setupTests.js',
|
||||
testTimeout: 10000
|
||||
}
|
||||
};
|
||||
});
|
Loading…
Add table
Reference in a new issue