diff --git a/README.md b/README.md index 27264f8d1..e1c8dbae1 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ A desktop app experience for building a block themes. ## Deving ```bash +$ nvm use $ npm install $ npm start ``` @@ -16,3 +17,9 @@ The app auto-opens and the Chromium developer tools are opened by default. `src/renderer.ts` is the entrypoint for the "renderer"—the code running in the Chromium window. Code formatting has been set up just to make merging PRs easier. It uses the same prettier/eslint mechanism as Calypso, see p4TIVU-9Lo-p2 for details on setting up your editor. + +## Building Installers + +```bash``` +$ npm run make +``` diff --git a/forge.config.ts b/forge.config.ts index 496b60720..18a0e9509 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -1,8 +1,14 @@ +// When ts-node runs this file it doesn't seem to use our tsconfig.json project +// settings, so we need to reference custom package definitions manually. +// eslint-disable-next-line @typescript-eslint/triple-slash-reference +/// + import type { ForgeConfig } from '@electron-forge/shared-types'; import { MakerZIP } from '@electron-forge/maker-zip'; import { MakerDMG } from '@electron-forge/maker-dmg'; import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives'; import { WebpackPlugin } from '@electron-forge/plugin-webpack'; +import ForgeExternalsPlugin from '@timfish/forge-externals-plugin'; import { mainConfig } from './webpack.main.config'; import { rendererConfig } from './webpack.renderer.config'; @@ -10,6 +16,7 @@ import { rendererConfig } from './webpack.renderer.config'; const config: ForgeConfig = { packagerConfig: { asar: true, + extraResource: [ './wp-files' ], }, rebuildConfig: {}, makers: [ new MakerZIP( {}, [ 'darwin' ] ), new MakerDMG( {}, [ 'darwin' ] ) ], @@ -34,6 +41,8 @@ const config: ForgeConfig = { port: parseInt( process.env.PORT, 10 ), } ), } ), + // This plugin bundles the externals defined in the Webpack config file. + new ForgeExternalsPlugin( { externals: Object.keys( mainConfig.externals ?? {} ) } ), ], }; diff --git a/package-lock.json b/package-lock.json index 0ebebee69..9ae271940 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,7 @@ "@php-wasm/node": "^0.5.4", "@wp-now/wp-now": "^0.1.63", "electron-squirrel-startup": "^1.0.0", - "file-stream-rotator": "^1.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "file-stream-rotator": "^1.0.0" }, "devDependencies": { "@electron-forge/cli": "^7.2.0", @@ -23,6 +21,7 @@ "@electron-forge/maker-zip": "^7.2.0", "@electron-forge/plugin-auto-unpack-natives": "^7.2.0", "@electron-forge/plugin-webpack": "^7.2.0", + "@timfish/forge-externals-plugin": "^0.2.1", "@types/react": "^18.2.42", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^5.0.0", @@ -41,6 +40,8 @@ "postcss": "^8.4.32", "postcss-loader": "^7.3.3", "prettier": "npm:wp-prettier@3.0.3", + "react": "^18.2.0", + "react-dom": "^18.2.0", "style-loader": "^3.0.0", "tailwindcss": "^3.3.6", "ts-loader": "^9.2.2", @@ -1284,6 +1285,60 @@ "node": ">=10" } }, + "node_modules/@timfish/forge-externals-plugin": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@timfish/forge-externals-plugin/-/forge-externals-plugin-0.2.1.tgz", + "integrity": "sha512-80TVZM4n/8x2zxT+SowyHJEzzQR0KLfmZpHg5UX2JnwR1WRa1h03Y7TUvV7PYD4P9/h3r+LcBZy6a7EsDwMtPg==", + "dev": true, + "dependencies": { + "flora-colossus": "1.0.1" + } + }, + "node_modules/@timfish/forge-externals-plugin/node_modules/flora-colossus": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-1.0.1.tgz", + "integrity": "sha512-d+9na7t9FyH8gBJoNDSi28mE4NgQVGGvxQ4aHtFRetjyh5SXjuus+V5EZaxFmFdXVemSOrx0lsgEl/ZMjnOWJA==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^7.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@timfish/forge-externals-plugin/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@timfish/forge-externals-plugin/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@timfish/forge-externals-plugin/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -7058,7 +7113,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", @@ -7385,6 +7441,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -9140,6 +9197,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -9151,6 +9209,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -9703,6 +9762,7 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -12842,6 +12902,53 @@ "defer-to-connect": "^2.0.0" } }, + "@timfish/forge-externals-plugin": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@timfish/forge-externals-plugin/-/forge-externals-plugin-0.2.1.tgz", + "integrity": "sha512-80TVZM4n/8x2zxT+SowyHJEzzQR0KLfmZpHg5UX2JnwR1WRa1h03Y7TUvV7PYD4P9/h3r+LcBZy6a7EsDwMtPg==", + "dev": true, + "requires": { + "flora-colossus": "1.0.1" + }, + "dependencies": { + "flora-colossus": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-1.0.1.tgz", + "integrity": "sha512-d+9na7t9FyH8gBJoNDSi28mE4NgQVGGvxQ4aHtFRetjyh5SXjuus+V5EZaxFmFdXVemSOrx0lsgEl/ZMjnOWJA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "fs-extra": "^7.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -17177,7 +17284,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "4.1.0", @@ -17432,6 +17540,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -18670,6 +18779,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -18678,6 +18788,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -19074,6 +19185,7 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, "requires": { "loose-envify": "^1.1.0" } diff --git a/package.json b/package.json index f5515877e..a5b7fc2d4 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@electron-forge/maker-zip": "^7.2.0", "@electron-forge/plugin-auto-unpack-natives": "^7.2.0", "@electron-forge/plugin-webpack": "^7.2.0", + "@timfish/forge-externals-plugin": "^0.2.1", "@types/react": "^18.2.42", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^5.0.0", @@ -44,6 +45,8 @@ "postcss": "^8.4.32", "postcss-loader": "^7.3.3", "prettier": "npm:wp-prettier@3.0.3", + "react": "^18.2.0", + "react-dom": "^18.2.0", "style-loader": "^3.0.0", "tailwindcss": "^3.3.6", "ts-loader": "^9.2.2", @@ -54,8 +57,6 @@ "@php-wasm/node": "^0.5.4", "@wp-now/wp-now": "^0.1.63", "electron-squirrel-startup": "^1.0.0", - "file-stream-rotator": "^1.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "file-stream-rotator": "^1.0.0" } } diff --git a/src/wp-now-definitions.d.ts b/src/custom-package-definitions.d.ts similarity index 55% rename from src/wp-now-definitions.d.ts rename to src/custom-package-definitions.d.ts index 28db0d563..982ed7455 100644 --- a/src/wp-now-definitions.d.ts +++ b/src/custom-package-definitions.d.ts @@ -11,3 +11,13 @@ declare module '@wp-now/wp-now' { function getWpNowConfig( ...args: any[] ): Promise< any >; function startServer( ...args: any[] ): Promise< Server >; } + +declare module '@timfish/forge-externals-plugin' { + import type { PluginBase } from '@electron-forge/plugin-base'; + + class ForgeExternalsPlugin extends PluginBase< { externals: string[] } > { + name: string; + } + + export = ForgeExternalsPlugin; +} diff --git a/src/index.ts b/src/index.ts index eeb5335c7..cfa88b069 100644 --- a/src/index.ts +++ b/src/index.ts @@ -130,8 +130,8 @@ app.on( 'ready', () => { const policies = [ "default-src 'self'", "script-src-attr 'none'", + "style-src 'self' 'unsafe-inline'", // unsafe-inline is used by tailwind process.env.NODE_ENV === 'development' && "script-src 'self' 'unsafe-eval'", // unsafe-eval is used by hot reloading - process.env.NODE_ENV === 'development' && "style-src 'self' 'unsafe-inline'", // unsafe-inline is used by tailwind ]; callback( { diff --git a/src/site-server.ts b/src/site-server.ts index 089527161..28e6643d3 100644 --- a/src/site-server.ts +++ b/src/site-server.ts @@ -2,6 +2,7 @@ import nodePath from 'path'; import { pathExists, recursiveCopyDirectory, isEmptyDir } from './fs-utils'; import { getWpNowConfig, startServer, type Server as WPNowServer } from '@wp-now/wp-now'; import { portFinder } from './port-finder'; +import { app } from 'electron'; const servers = new Map< string, SiteServer >(); @@ -11,11 +12,27 @@ export async function createSiteWorkingDirectory( path: string ): Promise< boole return false; } - await recursiveCopyDirectory( nodePath.resolve( 'wp-files/latest/wordpress' ), path ); + const wpFilesPath = nodePath.join( getResourcesPath(), 'wp-files', 'latest', 'wordpress' ); + + await recursiveCopyDirectory( wpFilesPath, path ); return true; } +function getResourcesPath(): string { + if ( process.env.NODE_ENV === 'development' ) { + return process.cwd(); + } + + const exePath = nodePath.dirname( app.getPath( 'exe' ) ); + + if ( process.platform === 'darwin' ) { + return nodePath.resolve( exePath, '..', 'Resources' ); + } + + return nodePath.join( exePath, 'resources' ); +} + export async function stopAllServersOnQuit() { // We're quitting so this doesn't have to be tidy, just stop the // servers as directly as possible. diff --git a/webpack.main.config.ts b/webpack.main.config.ts index f20ca8c8f..31990fcdb 100644 --- a/webpack.main.config.ts +++ b/webpack.main.config.ts @@ -18,10 +18,8 @@ export const mainConfig: Configuration = { extensions: [ '.js', '.ts', '.jsx', '.tsx', '.css', '.json' ], }, externals: { - /** - * We need to add PHP Wasm as an external because it uses the __dirname - * variable, and Webpack messes with it. - */ + // We need to add PHP Wasm as an external because it uses the __dirname + // variable, and Webpack messes with it. '@php-wasm/node': '@php-wasm/node', }, };