Added custom build setup
refs https://github.com/TryGhost/Team/issues/1664 - overrides webpack config to generate single script for publishing - adds custom scripts for dev and production mode
This commit is contained in:
parent
59865f1e0f
commit
cc4eda6478
1
apps/comments-ui/.env
Normal file
1
apps/comments-ui/.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
REACT_APP_VERSION=$npm_package_version
|
12
apps/comments-ui/.github/workflows/test.yml
vendored
Normal file
12
apps/comments-ui/.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
name: Test
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- 'renovate/*'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
uses: tryghost/actions/.github/workflows/test.yml@main
|
||||||
|
secrets:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
13
apps/comments-ui/.gitignore
vendored
13
apps/comments-ui/.gitignore
vendored
@ -69,3 +69,16 @@ typings/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# Comments Ui Custom
|
# Comments Ui Custom
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# Membersjs build folders
|
||||||
|
umd/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Allow .env file
|
||||||
|
!.env
|
||||||
|
## We use .env file to define NODE_PATH as recommended test-utils setup pattern to avoid relative imports.
|
||||||
|
# Refs: https://testing-library.com/docs/react-testing-library/setup#jest-and-create-react-app
|
||||||
|
# CRA also suggests `.env` files should be checked into source control
|
||||||
|
# Ref: https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-development-environment-variables-in-env
|
||||||
|
@ -5,24 +5,40 @@
|
|||||||
"repository": "git@github.com:TryGhost/comments-ui.git",
|
"repository": "git@github.com:TryGhost/comments-ui.git",
|
||||||
"author": "Ghost Foundation",
|
"author": "Ghost Foundation",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "5.16.2",
|
||||||
"@testing-library/react": "^13.0.0",
|
"@testing-library/react": "12.1.2",
|
||||||
"@testing-library/user-event": "^13.2.1",
|
"@testing-library/user-event": "14.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "17.0.2",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "17.0.2",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "4.0.3"
|
||||||
"web-vitals": "^2.1.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "BROWSER=none react-scripts start",
|
||||||
"build": "react-scripts build",
|
"start:combined": "BROWSER=none node ./scripts/start-combined.js",
|
||||||
"test": "react-scripts test",
|
"start:dev": "node ./scripts/start-mode.js",
|
||||||
"eject": "react-scripts eject"
|
"dev": "node ./scripts/dev-mode.js",
|
||||||
|
"build": "npm run build:combined",
|
||||||
|
"build:original": "react-scripts build",
|
||||||
|
"build:combined": "node ./scripts/build-combined.js",
|
||||||
|
"build:bundle": "webpack --config webpack.config.js",
|
||||||
|
"test:ui": "react-scripts test",
|
||||||
|
"test": "yarn test --watchAll=false --coverage",
|
||||||
|
"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 publish && git push ${GHOST_UPSTREAM:-upstream} main --follow-tags; fi",
|
||||||
|
"posttest": "yarn lint",
|
||||||
|
"analyze": "source-map-explorer 'umd/*.js'",
|
||||||
|
"prepublishOnly": "yarn build"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"react-app",
|
"react-app",
|
||||||
"react-app/jest"
|
"react-app/jest",
|
||||||
|
"plugin:ghost/browser"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"ghost"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
@ -36,5 +52,21 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"chalk": "4.1.2",
|
||||||
|
"chokidar": "3.5.2",
|
||||||
|
"copy-webpack-plugin": "6.4.1",
|
||||||
|
"eslint-plugin-ghost": "2.12.0",
|
||||||
|
"minimist": "1.2.5",
|
||||||
|
"ora": "5.4.1",
|
||||||
|
"rewire": "6.0.0",
|
||||||
|
"serve-handler": "6.1.3",
|
||||||
|
"source-map-explorer": "2.5.2",
|
||||||
|
"webpack-cli": "3.3.12"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"//": "See https://github.com/facebook/create-react-app/issues/11773",
|
||||||
|
"react-error-overlay": "6.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
apps/comments-ui/scripts/build-combined.js
Normal file
29
apps/comments-ui/scripts/build-combined.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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/comments-ui.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))
|
||||||
|
});
|
||||||
|
});
|
220
apps/comments-ui/scripts/dev-mode.js
Normal file
220
apps/comments-ui/scripts/dev-mode.js
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
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 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 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 printInstructions() {
|
||||||
|
log();
|
||||||
|
log(chalk.yellowBright.underline(`Add portal to your local Ghost config`));
|
||||||
|
printConfigInstruction();
|
||||||
|
log(chalk.cyanBright('='.repeat(50)));
|
||||||
|
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}`));
|
||||||
|
printInstructions();
|
||||||
|
watchFiles();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clearConsole({withHistory: false});
|
||||||
|
startDevServer();
|
8
apps/comments-ui/scripts/load-portal.js
Normal file
8
apps/comments-ui/scripts/load-portal.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/** 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');
|
14
apps/comments-ui/scripts/start-combined.js
Normal file
14
apps/comments-ui/scripts/start-combined.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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;
|
||||||
|
});
|
151
apps/comments-ui/scripts/start-mode.js
Normal file
151
apps/comments-ui/scripts/start-mode.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
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();
|
@ -1,23 +1,9 @@
|
|||||||
import logo from './logo.svg';
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
Hello world
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
className="App-link"
|
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,54 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
|
||||||
import reportWebVitals from './reportWebVitals';
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
const ROOT_DIV_ID = 'ghost-comments-root';
|
||||||
root.render(
|
|
||||||
<React.StrictMode>
|
|
||||||
<App />
|
|
||||||
</React.StrictMode>
|
|
||||||
);
|
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
function addRootDiv() {
|
||||||
// to log results (for example: reportWebVitals(console.log))
|
const elem = document.createElement('div');
|
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
elem.id = ROOT_DIV_ID;
|
||||||
reportWebVitals();
|
document.body.appendChild(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSiteData() {
|
||||||
|
/**
|
||||||
|
* @type {HTMLElement}
|
||||||
|
*/
|
||||||
|
const scriptTag = document.querySelector('script[data-ghost]');
|
||||||
|
if (scriptTag) {
|
||||||
|
const siteUrl = scriptTag.dataset.ghost;
|
||||||
|
const apiKey = scriptTag.dataset.key;
|
||||||
|
const apiUrl = scriptTag.dataset.api;
|
||||||
|
return {siteUrl, apiKey, apiUrl};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTokenUrl() {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
if (url.searchParams.get('token')) {
|
||||||
|
url.searchParams.delete('token');
|
||||||
|
window.history.replaceState({}, document.title, url.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup({siteUrl}) {
|
||||||
|
addRootDiv();
|
||||||
|
handleTokenUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// const customSiteUrl = getSiteUrl();
|
||||||
|
const {siteUrl: customSiteUrl} = getSiteData();
|
||||||
|
const siteUrl = customSiteUrl || window.location.origin;
|
||||||
|
setup({siteUrl});
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
Hello World
|
||||||
|
{/* <App siteUrl={siteUrl} customSiteUrl={customSiteUrl} apiKey={apiKey} apiUrl={apiUrl} /> */}
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById(ROOT_DIV_ID)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
34
apps/comments-ui/webpack.config.js
Normal file
34
apps/comments-ui/webpack.config.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const glob = require('glob');
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: {
|
||||||
|
'bundle.js': glob.sync('build/static/?(js|css)/main.*.?(js|css)').map(f => path.resolve(__dirname, f))
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'comments-ui.min.js',
|
||||||
|
path: __dirname + '/umd'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ['style-loader', 'css-loader']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [
|
||||||
|
{from: './build/static/js/main.js.map', to: './umd/comments-ui.min.js.map'}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
performance: {
|
||||||
|
hints: false,
|
||||||
|
maxEntrypointSize: 560,
|
||||||
|
maxAssetSize: 5600
|
||||||
|
}
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user