diff --git a/README.md b/README.md index 3935d01..254bc27 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ ## Still Up To Date! -May 6, 2020 +August 18, 2025
-Just wanted to note that version [v3.4.1](https://github.com/facebook/create-react-app/releases/tag/v3.4.1) of [Create-React-App](https://create-react-app.dev/) is still the latest. +As of now, version [v5.1.0](https://github.com/facebook/create-react-app/releases/tag/v5.1.0) of [Create React App](https://create-react-app.dev/) is the latest release. If you have a theme made with an earlier version of `create-react-wptheme` and want to update it to the latest code, [just follow these instructions](#updating-existing-themes). @@ -99,6 +99,17 @@ So for example, if the tutorial instructs you to edit the `src/App.js` file, the `/react-src/src/App.js` +Since Create React App automatically resolves `.jsx` extensions, you can drop an `App.jsx` file right next to `index.js` without any extra configuration. A basic folder layout might look like: + +``` +react-src/ +└─ src/ + ├─ index.js + └─ App.jsx +``` + +From inside the `react-src` directory run `npm start` to develop locally or `npm run build` to create an optimized production build with the `.jsx` entry point. + ### The Public Folder The authors of the original `create-react-app` say that using the "Public" folder (found at `react-src/public` in your new theme's folder) is a last ditch "escape hatch" for adding otherwise-hard-to-deal-with files. diff --git a/packages/cra-template-wptheme-typescript/package.json b/packages/cra-template-wptheme-typescript/package.json index 9c93754..42bb47a 100644 --- a/packages/cra-template-wptheme-typescript/package.json +++ b/packages/cra-template-wptheme-typescript/package.json @@ -1,6 +1,6 @@ { "name": "cra-template-wptheme-typescript", - "version": "3.4.1-wp.1", + "version": "5.0.1-wp.1", "keywords": [ "react", "create-react-app", @@ -17,7 +17,7 @@ }, "license": "MIT", "engines": { - "node": ">=8.10" + "node": ">=14" }, "bugs": { "url": "https://github.com/devloco/create-react-wptheme/issues" diff --git a/packages/cra-template-wptheme-typescript/template.json b/packages/cra-template-wptheme-typescript/template.json index 1bb8826..4c7794d 100644 --- a/packages/cra-template-wptheme-typescript/template.json +++ b/packages/cra-template-wptheme-typescript/template.json @@ -1,14 +1,15 @@ { "package": { "dependencies": { - "@testing-library/react": "^9.3.2", - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/user-event": "^7.1.2", - "@types/node": "^12.0.0", - "@types/react": "^16.9.0", - "@types/react-dom": "^16.9.0", - "@types/jest": "^24.0.0", - "typescript": "~3.7.2" + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.18.11", + "@types/react": "^18.0.27", + "@types/react-dom": "^18.0.10", + "typescript": "^4.9.5", + "web-vitals": "^2.1.4" } } } diff --git a/packages/cra-template-wptheme-typescript/template/src/index.tsx b/packages/cra-template-wptheme-typescript/template/src/index.tsx index f5185c1..da6faa4 100644 --- a/packages/cra-template-wptheme-typescript/template/src/index.tsx +++ b/packages/cra-template-wptheme-typescript/template/src/index.tsx @@ -1,17 +1,17 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; -import * as serviceWorker from './serviceWorker'; +import reportWebVitals from './reportWebVitals'; -ReactDOM.render( +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( - , - document.getElementById('root') + ); -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); +// Log web vitals for performance measurements. +reportWebVitals(); diff --git a/packages/cra-template-wptheme-typescript/template/src/reportWebVitals.ts b/packages/cra-template-wptheme-typescript/template/src/reportWebVitals.ts new file mode 100644 index 0000000..49a2a16 --- /dev/null +++ b/packages/cra-template-wptheme-typescript/template/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/packages/cra-template-wptheme-typescript/template/src/serviceWorker.ts b/packages/cra-template-wptheme-typescript/template/src/serviceWorker.ts deleted file mode 100644 index b09523f..0000000 --- a/packages/cra-template-wptheme-typescript/template/src/serviceWorker.ts +++ /dev/null @@ -1,149 +0,0 @@ -// This optional code is used to register a service worker. -// register() is not called by default. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the -// existing tabs open on the page have been closed, since previously cached -// resources are updated in the background. - -// To learn more about the benefits of this model and instructions on how to -// opt-in, read https://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -type Config = { - onSuccess?: (registration: ServiceWorkerRegistration) => void; - onUpdate?: (registration: ServiceWorkerRegistration) => void; -}; - -export function register(config?: Config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL( - process.env.PUBLIC_URL, - window.location.href - ); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); - } -} - -function registerValidSW(swUrl: string, config?: Config) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker == null) { - return; - } - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' - ); - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration); - } - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration); - } - } - } - }; - }; - }) - .catch(error => { - console.error('Error during service worker registration:', error); - }); -} - -function checkValidServiceWorker(swUrl: string, config?: Config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl, { - headers: { 'Service-Worker': 'script' } - }) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); - if ( - response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); - } - }) - .catch(() => { - console.log( - 'No internet connection found. App is running in offline mode.' - ); - }); -} - -export function unregister() { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready - .then(registration => { - registration.unregister(); - }) - .catch(error => { - console.error(error.message); - }); - } -} diff --git a/packages/cra-template-wptheme-typescript/template/src/setupTests.ts b/packages/cra-template-wptheme-typescript/template/src/setupTests.ts index 74b1a27..8f2609b 100644 --- a/packages/cra-template-wptheme-typescript/template/src/setupTests.ts +++ b/packages/cra-template-wptheme-typescript/template/src/setupTests.ts @@ -2,4 +2,4 @@ // 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'; +import '@testing-library/jest-dom'; diff --git a/packages/cra-template-wptheme/package.json b/packages/cra-template-wptheme/package.json index a2d6d6c..fc5aeff 100644 --- a/packages/cra-template-wptheme/package.json +++ b/packages/cra-template-wptheme/package.json @@ -1,6 +1,6 @@ { "name": "cra-template-wptheme", - "version": "3.4.1-wp.1", + "version": "5.0.1-wp.1", "keywords": [ "wordpress", "create-react-app", @@ -25,7 +25,7 @@ }, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14" }, "bugs": { "url": "https://github.com/devloco/create-react-wptheme/issues" diff --git a/packages/cra-template-wptheme/template.json b/packages/cra-template-wptheme/template.json index 4c6861d..70b0283 100644 --- a/packages/cra-template-wptheme/template.json +++ b/packages/cra-template-wptheme/template.json @@ -1,9 +1,10 @@ { "package": { "dependencies": { - "@testing-library/react": "^9.3.2", - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/user-event": "^7.1.2" + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "web-vitals": "^2.1.4" } } } diff --git a/packages/cra-template-wptheme/template/src/App.js b/packages/cra-template-wptheme/template/src/App.jsx similarity index 86% rename from packages/cra-template-wptheme/template/src/App.js rename to packages/cra-template-wptheme/template/src/App.jsx index f31200d..d7fcc7e 100644 --- a/packages/cra-template-wptheme/template/src/App.js +++ b/packages/cra-template-wptheme/template/src/App.jsx @@ -8,7 +8,7 @@ function App() {
logo

- Edit react-src/src/App.js and save to reload. + Edit react-src/src/App.jsx and save to reload.

Learn React diff --git a/packages/cra-template-wptheme/template/src/index.js b/packages/cra-template-wptheme/template/src/index.js index f5185c1..11be3b4 100644 --- a/packages/cra-template-wptheme/template/src/index.js +++ b/packages/cra-template-wptheme/template/src/index.js @@ -1,17 +1,16 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import './index.css'; -import App from './App'; -import * as serviceWorker from './serviceWorker'; +// Explicitly import the JSX component to avoid resolution issues. +import App from './App.jsx'; +import reportWebVitals from './reportWebVitals'; -ReactDOM.render( +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render( - , - document.getElementById('root') + ); -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); +// Log web vitals for performance measurements. +reportWebVitals(); diff --git a/packages/cra-template-wptheme/template/src/reportWebVitals.js b/packages/cra-template-wptheme/template/src/reportWebVitals.js new file mode 100644 index 0000000..5253d3a --- /dev/null +++ b/packages/cra-template-wptheme/template/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/packages/cra-template-wptheme/template/src/serviceWorker.js b/packages/cra-template-wptheme/template/src/serviceWorker.js deleted file mode 100644 index b04b771..0000000 --- a/packages/cra-template-wptheme/template/src/serviceWorker.js +++ /dev/null @@ -1,141 +0,0 @@ -// This optional code is used to register a service worker. -// register() is not called by default. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the -// existing tabs open on the page have been closed, since previously cached -// resources are updated in the background. - -// To learn more about the benefits of this model and instructions on how to -// opt-in, read https://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -export function register(config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); - } -} - -function registerValidSW(swUrl, config) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker == null) { - return; - } - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' - ); - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration); - } - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration); - } - } - } - }; - }; - }) - .catch(error => { - console.error('Error during service worker registration:', error); - }); -} - -function checkValidServiceWorker(swUrl, config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl, { - headers: { 'Service-Worker': 'script' }, - }) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); - if ( - response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); - } - }) - .catch(() => { - console.log( - 'No internet connection found. App is running in offline mode.' - ); - }); -} - -export function unregister() { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready - .then(registration => { - registration.unregister(); - }) - .catch(error => { - console.error(error.message); - }); - } -} diff --git a/packages/cra-template-wptheme/template/src/setupTests.js b/packages/cra-template-wptheme/template/src/setupTests.js index 74b1a27..8f2609b 100644 --- a/packages/cra-template-wptheme/template/src/setupTests.js +++ b/packages/cra-template-wptheme/template/src/setupTests.js @@ -2,4 +2,4 @@ // 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'; +import '@testing-library/jest-dom'; diff --git a/packages/create-react-wptheme-utils/package.json b/packages/create-react-wptheme-utils/package.json index 866c87c..75c3e6c 100644 --- a/packages/create-react-wptheme-utils/package.json +++ b/packages/create-react-wptheme-utils/package.json @@ -3,7 +3,7 @@ "version": "3.4.1-wp.2", "description": "Utilities used by create-react-wptheme.", "engines": { - "node": ">=8" + "node": ">=14" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" @@ -28,11 +28,11 @@ "wpThemeServer.js" ], "dependencies": { - "chalk": "2.4.2", - "chokidar": "^3.3.1", - "shelljs": "^0.8.3", - "fs-extra": "^8.1.0", - "ws": "^7.2.3" + "chalk": "^5.6.0", + "chokidar": "^4.0.3", + "shelljs": "0.8.5", + "fs-extra": "^11.3.1", + "ws": "^8.18.3" }, "devDependencies": {} } diff --git a/packages/create-react-wptheme/createReactWpTheme.js b/packages/create-react-wptheme/createReactWpTheme.js index a7e5f3f..fcdf9db 100644 --- a/packages/create-react-wptheme/createReactWpTheme.js +++ b/packages/create-react-wptheme/createReactWpTheme.js @@ -20,7 +20,7 @@ // tell people to update their global version of create-react-wptheme. // // Also be careful with new language features. -// This file must work on Node 6+. +// This file must work on Node 14+. // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // /!\ DO NOT MODIFY THIS FILE /!\ @@ -37,13 +37,18 @@ const execSync = require("child_process").execSync; const spawn = require("cross-spawn"); const dns = require("dns"); const url = require("url"); +const envinfo = require("envinfo"); const packageJson = require("./package.json"); const _wpThemeVersion = packageJson.version; const _createReactAppVersion = _wpThemeVersion.split("-wp.")[0]; // Check these!!!! -const _reactScriptsWpThemeVersion = "^3.4.1-wp.1"; +// React 18 requires a newer build setup such as CRA 5 which ships with +// react-scripts@5.0.1. Update the default scripts version so newly +// generated themes are compatible with React 18 features like +// `react-dom/client`. +const _reactScriptsWpThemeVersion = "^5.0.1"; const _getScriptsPath = function () { return scriptsFromNpm(); }; @@ -51,7 +56,7 @@ const _getScriptsPath = function () { const scriptsFromNpm = function () { //console.log("SCRIPTS FROM NPM"); return { - path: `@devloco/react-scripts-wptheme@${_reactScriptsWpThemeVersion}`, + path: `react-scripts@${_reactScriptsWpThemeVersion}`, }; }; @@ -93,7 +98,7 @@ const scriptsFromGit = function () { let projectName; const program = new commander.Command(packageJson.name) .version(packageJson.version) - .arguments("") + .argument("[project-directory]") .usage(`${chalk.green("")} [options]`) .action((name) => { projectName = name; @@ -113,7 +118,9 @@ const program = new commander.Command(packageJson.name) }) .parse(process.argv); -if (program.info) { +const options = program.opts(); + +if (options.info) { console.log(chalk.bold("\nEnvironment Info:")); return envinfo .run( @@ -152,9 +159,9 @@ function printValidationResults(results) { } console.log(program.name() + " version: " + chalk.magenta(_wpThemeVersion)); -console.log("@devloco/react-scripts-wptheme version: " + chalk.magenta(_reactScriptsWpThemeVersion)); +console.log("react-scripts version: " + chalk.magenta(_reactScriptsWpThemeVersion)); console.log(); -createApp(projectName, program.verbose, program.scriptsVersion, program.useNpm, program.usePnp, program.typescript); +createApp(projectName, options.verbose, options.scriptsVersion, options.useNpm, options.usePnp, options.typescript); function createApp(name, verbose, version, useNpm, usePnp, useTypescript, template) { const root = path.resolve(name); diff --git a/packages/create-react-wptheme/index.js b/packages/create-react-wptheme/index.js index 803927c..e14f5d8 100644 --- a/packages/create-react-wptheme/index.js +++ b/packages/create-react-wptheme/index.js @@ -32,9 +32,9 @@ var currentNodeVersion = process.versions.node; var semver = currentNodeVersion.split("."); var major = semver[0]; -if (major < 8) { +if (major < 14) { console.error(chalk.red(`You are running Node ${currentNodeVersion}.`)); - console.error(chalk.red("Create React WP Theme requires Node 8 or higher.")); + console.error(chalk.red("Create React WP Theme requires Node 14 or higher.")); console.error(chalk.red("Please update your version of Node.")); process.exit(1); } diff --git a/packages/create-react-wptheme/package.json b/packages/create-react-wptheme/package.json index df001f7..bf15fae 100644 --- a/packages/create-react-wptheme/package.json +++ b/packages/create-react-wptheme/package.json @@ -1,6 +1,6 @@ { "name": "create-react-wptheme", - "version": "3.4.1-wp.1", + "version": "5.0.1-wp.1", "description": "Create React-enabled WP themes.", "main": "index.js", "scripts": { @@ -28,7 +28,7 @@ "author": "devloco", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14" }, "bugs": { "url": "https://github.com/devloco/create-react-wptheme/issues" @@ -42,13 +42,13 @@ "create-react-wptheme": "./index.js" }, "dependencies": { - "chalk": "3.0.0", - "commander": "2.20.0", - "cross-spawn": "6.0.5", - "envinfo": "7.3.1", - "fs-extra": "7.0.1", - "semver": "6.3.0", - "tmp": "0.0.33", - "validate-npm-package-name": "3.0.0" + "chalk": "4.1.2", + "commander": "^9.5.0", + "cross-spawn": "7.0.6", + "envinfo": "7.14.0", + "fs-extra": "11.3.1", + "semver": "7.7.2", + "tmp": "0.2.5", + "validate-npm-package-name": "6.0.2" } }