diff --git a/.eslintignore b/.eslintignore index 4dfb13b84..7fdcc7018 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,9 @@ /cli/assets **/locales/index.js -cli/config/init.entrypoint.js -cli/config/init.App.test.js +# These are to avoid lint errors like 'cannot find module App.jsx' +cli/config/templates/init/entrypoint.jsx +cli/config/templates/init/App.test.jsx +cli/config/templates/init-typescript/entrypoint.tsx +cli/config/templates/init-typescript/App.test.tsx +cli/config/templates/init-typescript/global.d.ts +cli/config/templates/init-typescript/modules.d.ts diff --git a/.github/workflows/dhis2-deploy-netlify.yml b/.github/workflows/dhis2-deploy-netlify.yml index 1b8bf10ab..10bf297f0 100644 --- a/.github/workflows/dhis2-deploy-netlify.yml +++ b/.github/workflows/dhis2-deploy-netlify.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 18.x - uses: c-hive/gha-yarn-cache@v1 - run: yarn install --frozen-lockfile diff --git a/.github/workflows/dhis2-verify-lib.yml b/.github/workflows/dhis2-verify-lib.yml index 5cd4020e8..bd351aeda 100644 --- a/.github/workflows/dhis2-verify-lib.yml +++ b/.github/workflows/dhis2-verify-lib.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 18.x - uses: c-hive/gha-yarn-cache@v1 - run: yarn install --frozen-lockfile @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 18.x - uses: c-hive/gha-yarn-cache@v1 - run: yarn install --frozen-lockfile @@ -59,7 +59,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 18.x - uses: actions/download-artifact@v4 with: @@ -81,7 +81,7 @@ jobs: token: ${{env.GH_TOKEN}} - uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 18.x - uses: actions/download-artifact@v4 with: @@ -90,6 +90,10 @@ jobs: - uses: c-hive/gha-yarn-cache@v1 - run: yarn install --frozen-lockfile + # If npm > v7, the semantic release action below modifies yarn.lock + # upon release (since it runs `npm version ___`) + - run: npm install -g npm@^6 + - uses: dhis2/action-semantic-release@master with: publish-npm: true diff --git a/.gitignore b/.gitignore index c7420b8b0..90b115a20 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ cli/assets # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7bcbf76..541dd57e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,100 +1,135 @@ -## [11.7.5](https://github.com/dhis2/app-platform/compare/v11.7.4...v11.7.5) (2024-11-04) +# [12.0.0-alpha.29](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.28...v12.0.0-alpha.29) (2024-12-11) ### Bug Fixes -* **publishVersion:** fix maxBodyLength when uploading to appHub ([c5abfd1](https://github.com/dhis2/app-platform/commit/c5abfd10d2ad04c09797cec2c2abb1a823d93dd9)) +* **deps:** use npm v6 before publishing ([01ad502](https://github.com/dhis2/app-platform/commit/01ad502f039b917e53268fb8b9ec73f14ccf84bc)) -## [11.7.4](https://github.com/dhis2/app-platform/compare/v11.7.3...v11.7.4) (2024-10-22) +# [12.0.0-alpha.28](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.27...v12.0.0-alpha.28) (2024-12-11) ### Bug Fixes -* bump typescript version used in app shell ([8ebb2e8](https://github.com/dhis2/app-platform/commit/8ebb2e8dc46e2747b71226906bf0565eb041bb66)) +* **deps:** upgrade react to 18 in example apps ([#900](https://github.com/dhis2/app-platform/issues/900)) ([7fd16d7](https://github.com/dhis2/app-platform/commit/7fd16d7fa347a804d9c78ae86976859fef54632b)) -## [11.7.3](https://github.com/dhis2/app-platform/compare/v11.7.2...v11.7.3) (2024-10-21) +# [12.0.0-alpha.27](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.26...v12.0.0-alpha.27) (2024-12-10) ### Bug Fixes -* add @babel/plugin-syntax-dynamic-import as a direct dependency ([#886](https://github.com/dhis2/app-platform/issues/886)) ([8c5ef0c](https://github.com/dhis2/app-platform/commit/8c5ef0c394a6cd639daefaae44c786f4919ebd62)) +* **init:** update bootstrap script branch ([#896](https://github.com/dhis2/app-platform/issues/896)) ([33c261a](https://github.com/dhis2/app-platform/commit/33c261a1f33b02b46605b48260987e5d09920227)) +* **plugin:** clean up resize observer and handle sonarqube warnings ([#898](https://github.com/dhis2/app-platform/issues/898)) ([f113dd5](https://github.com/dhis2/app-platform/commit/f113dd5a1ddea58a2f3e94a15c7075a95fee823e)) -## [11.7.2](https://github.com/dhis2/app-platform/compare/v11.7.1...v11.7.2) (2024-09-26) +# [12.0.0-alpha.26](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.25...v12.0.0-alpha.26) (2024-12-06) ### Bug Fixes -* provide fallback api version [LIBS-683] ([#877](https://github.com/dhis2/app-platform/issues/877)) ([dc7bdfa](https://github.com/dhis2/app-platform/commit/dc7bdfab893bdf44ad439e49b25ad3611191ad7a)) +* **deps:** upgrade app-runtime and ui ([#895](https://github.com/dhis2/app-platform/issues/895)) ([8ed0ec3](https://github.com/dhis2/app-platform/commit/8ed0ec3b2e3468d256c7ca5f335c43fcfd040ef6)) + +# [12.0.0-alpha.25](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.24...v12.0.0-alpha.25) (2024-11-21) + + +### Bug Fixes + +* clear only required build dirs ([#894](https://github.com/dhis2/app-platform/issues/894)) ([179305f](https://github.com/dhis2/app-platform/commit/179305ff268a215f0bd0ea1f8edd39f3e3ecbba3)) + +# [12.0.0-alpha.24](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.23...v12.0.0-alpha.24) (2024-11-21) -## [11.7.1](https://github.com/dhis2/app-platform/compare/v11.7.0...v11.7.1) (2024-08-27) + +### Bug Fixes + +* normalize to .js extensions when compiling libraries ([#893](https://github.com/dhis2/app-platform/issues/893)) ([58b33a8](https://github.com/dhis2/app-platform/commit/58b33a812ba22e58a966a535c432dafea4cb8880)) + +# [12.0.0-alpha.23](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.22...v12.0.0-alpha.23) (2024-11-08) ### Bug Fixes +* **service-worker:** handle undefined config vars in injectPrecacheManifest ([a90a4e0](https://github.com/dhis2/app-platform/commit/a90a4e06b25cdecfaf31f24dc51f28c98f20d122)) + +# [12.0.0-alpha.22](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.21...v12.0.0-alpha.22) (2024-11-06) + + +### Bug Fixes + +* **publishVersion:** fix maxBodyLength when uploading to appHub ([c5abfd1](https://github.com/dhis2/app-platform/commit/c5abfd10d2ad04c09797cec2c2abb1a823d93dd9)) +* add @babel/plugin-syntax-dynamic-import as a direct dependency ([#886](https://github.com/dhis2/app-platform/issues/886)) ([8c5ef0c](https://github.com/dhis2/app-platform/commit/8c5ef0c394a6cd639daefaae44c786f4919ebd62)) +* bump typescript version used in app shell ([8ebb2e8](https://github.com/dhis2/app-platform/commit/8ebb2e8dc46e2747b71226906bf0565eb041bb66)) +* provide fallback api version [LIBS-683] ([#877](https://github.com/dhis2/app-platform/issues/877)) ([dc7bdfa](https://github.com/dhis2/app-platform/commit/dc7bdfab893bdf44ad439e49b25ad3611191ad7a)) * update app-runtime dependency ([74a2165](https://github.com/dhis2/app-platform/commit/74a21655bee64c9ca4e6285486b4fabb8bc76959)) -# [11.7.0](https://github.com/dhis2/app-platform/compare/v11.6.4...v11.7.0) (2024-07-23) +## [11.7.5](https://github.com/dhis2/app-platform/compare/v11.7.4...v11.7.5) (2024-11-04) -### Features +### Bug Fixes -* update boilerplate app code for init command [LIBS-644] ([#866](https://github.com/dhis2/app-platform/issues/866)) ([bd6cfc0](https://github.com/dhis2/app-platform/commit/bd6cfc0d132b40c91b44fcdc715befabf2d7e4cf)) +* **publishVersion:** fix maxBodyLength when uploading to appHub ([c5abfd1](https://github.com/dhis2/app-platform/commit/c5abfd10d2ad04c09797cec2c2abb1a823d93dd9)) -## [11.6.4](https://github.com/dhis2/app-platform/compare/v11.6.3...v11.6.4) (2024-07-19) +## [11.7.4](https://github.com/dhis2/app-platform/compare/v11.7.3...v11.7.4) (2024-10-22) ### Bug Fixes -* use i18next-scanner v3 for better i18next compatibility ([#864](https://github.com/dhis2/app-platform/issues/864)) ([84a5a59](https://github.com/dhis2/app-platform/commit/84a5a59747eef82ec85eb602cfef9040efc8fd8a)) +* bump typescript version used in app shell ([8ebb2e8](https://github.com/dhis2/app-platform/commit/8ebb2e8dc46e2747b71226906bf0565eb041bb66)) -## [11.6.3](https://github.com/dhis2/app-platform/compare/v11.6.2...v11.6.3) (2024-07-16) +## [11.7.3](https://github.com/dhis2/app-platform/compare/v11.7.2...v11.7.3) (2024-10-21) ### Bug Fixes -* **deps:** update i18next-scanner version to support old plurals format again ([#861](https://github.com/dhis2/app-platform/issues/861)) ([d0e433b](https://github.com/dhis2/app-platform/commit/d0e433bf0ca213641770e68cf8beb0780570e5c3)) +* add @babel/plugin-syntax-dynamic-import as a direct dependency ([#886](https://github.com/dhis2/app-platform/issues/886)) ([8c5ef0c](https://github.com/dhis2/app-platform/commit/8c5ef0c394a6cd639daefaae44c786f4919ebd62)) -## [11.6.2](https://github.com/dhis2/app-platform/compare/v11.6.1...v11.6.2) (2024-07-10) +## [11.7.2](https://github.com/dhis2/app-platform/compare/v11.7.1...v11.7.2) (2024-09-26) ### Bug Fixes -* plugin boundary retry if plugin logic is skipped ([#862](https://github.com/dhis2/app-platform/issues/862)) ([01a3160](https://github.com/dhis2/app-platform/commit/01a3160242a8352f0bcde229b3e860e396ff5be5)) +* provide fallback api version [LIBS-683] ([#877](https://github.com/dhis2/app-platform/issues/877)) ([dc7bdfa](https://github.com/dhis2/app-platform/commit/dc7bdfab893bdf44ad439e49b25ad3611191ad7a)) -## [11.6.1](https://github.com/dhis2/app-platform/compare/v11.6.0...v11.6.1) (2024-07-05) +## [11.7.1](https://github.com/dhis2/app-platform/compare/v11.7.0...v11.7.1) (2024-08-27) ### Bug Fixes -* **alerts:** ensure hiding works correctly and alerts are not re-added [DHIS2-15438] ([#859](https://github.com/dhis2/app-platform/issues/859)) ([6b11fff](https://github.com/dhis2/app-platform/commit/6b11fff033cc16ed4d2f11caf74e8c18307abc3c)) +* update app-runtime dependency ([74a2165](https://github.com/dhis2/app-platform/commit/74a21655bee64c9ca4e6285486b4fabb8bc76959)) -# [11.6.0](https://github.com/dhis2/app-platform/compare/v11.5.1...v11.6.0) (2024-07-03) +# [11.7.0](https://github.com/dhis2/app-platform/compare/v11.6.4...v11.7.0) (2024-07-23) ### Features -* parse additional namespaces from `d2.config.js` and add to `manifest.webapp` [LIBS-638] ([#860](https://github.com/dhis2/app-platform/issues/860)) ([62782fe](https://github.com/dhis2/app-platform/commit/62782fed6f59a439ab2ef7f00c7e7d88110a78bf)) +* update boilerplate app code for init command [LIBS-644] ([#866](https://github.com/dhis2/app-platform/issues/866)) ([bd6cfc0](https://github.com/dhis2/app-platform/commit/bd6cfc0d132b40c91b44fcdc715befabf2d7e4cf)) -## [11.5.1](https://github.com/dhis2/app-platform/compare/v11.5.0...v11.5.1) (2024-07-01) +# [12.0.0-alpha.3](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.2...v12.0.0-alpha.3) (2024-07-08) ### Bug Fixes +* **alerts:** ensure hiding works correctly and alerts are not re-added [DHIS2-15438] ([#859](https://github.com/dhis2/app-platform/issues/859)) ([6b11fff](https://github.com/dhis2/app-platform/commit/6b11fff033cc16ed4d2f11caf74e8c18307abc3c)) * fixed dimensions plugins [LIBS-634] ([#858](https://github.com/dhis2/app-platform/issues/858)) ([1f717f3](https://github.com/dhis2/app-platform/commit/1f717f391b96a88186c897b9b886e11d6168c87c)) - -# [11.5.0](https://github.com/dhis2/app-platform/compare/v11.4.3...v11.5.0) (2024-06-24) +* small text change in changelog ([824dd2f](https://github.com/dhis2/app-platform/commit/824dd2f877d03a7c4d492dff8999e72421297165)) ### Features * cleanup plugin error boundary [UX-136] ([#856](https://github.com/dhis2/app-platform/issues/856)) ([de252fe](https://github.com/dhis2/app-platform/commit/de252fef91c5037b8b1c238ce25c7e3b90f7c20e)) +* parse additional namespaces from `d2.config.js` and add to `manifest.webapp` [LIBS-638] ([#860](https://github.com/dhis2/app-platform/issues/860)) ([62782fe](https://github.com/dhis2/app-platform/commit/62782fed6f59a439ab2ef7f00c7e7d88110a78bf)) -## [11.4.3](https://github.com/dhis2/app-platform/compare/v11.4.2...v11.4.3) (2024-06-24) +# [12.0.0-alpha.2](https://github.com/dhis2/app-platform/compare/v12.0.0-alpha.1...v12.0.0-alpha.2) (2024-06-20) ### Bug Fixes -* small text change in changelog ([824dd2f](https://github.com/dhis2/app-platform/commit/824dd2f877d03a7c4d492dff8999e72421297165)) +* clean up for plugins [LIBS-620] ([#851](https://github.com/dhis2/app-platform/issues/851)) ([13af3b5](https://github.com/dhis2/app-platform/commit/13af3b5ee862ea4b7952c6a9199505cfe6a1bdaa)) +* do not encode username, password ([#852](https://github.com/dhis2/app-platform/issues/852)) ([2fb4272](https://github.com/dhis2/app-platform/commit/2fb4272130000b383c91d46ba1b3dac44bb13ebf)) +* don't start plugins for apps without a plugin entrypoint ([#850](https://github.com/dhis2/app-platform/issues/850)) ([a89d4cf](https://github.com/dhis2/app-platform/commit/a89d4cf348f7edc0a52b8ab9aacf96f2de939de4)) + + +### Features + +* parse pluginType from d2 config to add to manifest.webapp ([#849](https://github.com/dhis2/app-platform/issues/849)) ([c1dae23](https://github.com/dhis2/app-platform/commit/c1dae238b92183922962811a52ab50d1b73e7995)) +* start plugin and app separately [LIBS-391] [LIBS-392] ([#848](https://github.com/dhis2/app-platform/issues/848)) ([82003e7](https://github.com/dhis2/app-platform/commit/82003e73fce995a83318c623da6028d9975e6686)) ## [11.4.2](https://github.com/dhis2/app-platform/compare/v11.4.1...v11.4.2) (2024-06-18) diff --git a/adapter/package.json b/adapter/package.json index d350e352f..f38733864 100644 --- a/adapter/package.json +++ b/adapter/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/app-adapter", - "version": "11.7.5", + "version": "12.0.0-alpha.29", "repository": { "type": "git", "url": "https://github.com/amcgee/dhis2-app-platform", @@ -21,31 +21,31 @@ "build" ], "dependencies": { - "@dhis2/pwa": "11.7.5", + "@dhis2/pwa": "12.0.0-alpha.29", "moment": "^2.24.0" }, "devDependencies": { - "@dhis2/cli-app-scripts": "11.7.5", - "@testing-library/react": "^12.0.0", - "@testing-library/react-hooks": "^8.0.1", + "@dhis2/cli-app-scripts": "12.0.0-alpha.29", + "@testing-library/react": "^16.0.1", + "@testing-library/dom": "^10.4.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", - "react": "^16.8", - "react-dom": "^16.8" + "react": "^18", + "react-dom": "^18" }, "scripts": { "build": "d2-app-scripts build", "test": "d2-app-scripts test" }, "peerDependencies": { - "@dhis2/app-runtime": "^3.10.4", + "@dhis2/app-runtime": "^3.11.1", "@dhis2/d2-i18n": "^1", - "@dhis2/ui": ">=9.8.9", + "@dhis2/ui": ">=10.1.7", "classnames": "^2", "moment": "^2", "prop-types": "^15", - "react": "^16.8", - "react-dom": "^16.8", + "react": "^18", + "react-dom": "^18", "styled-jsx": "^4" }, "jest": { diff --git a/adapter/src/utils/localeUtils.js b/adapter/src/utils/localeUtils.js index aa52f6a9a..6f2d57fb1 100644 --- a/adapter/src/utils/localeUtils.js +++ b/adapter/src/utils/localeUtils.js @@ -132,9 +132,10 @@ export const setMomentLocale = async (locale) => { for (const localeName of localeNameOptions) { try { - await import( - /* webpackChunkName: "moment-locales/[request]" */ `moment/locale/${localeName}` - ) + // Since Vite prefers importing the ESM form of moment, we need + // to import the ESM form of the locales here to use the same + // moment instance + await import(`moment/dist/locale/${localeName}`) moment.locale(localeName) break } catch { diff --git a/adapter/src/utils/useLocale.test.js b/adapter/src/utils/useLocale.test.js index e9bc87cdb..c837eb980 100644 --- a/adapter/src/utils/useLocale.test.js +++ b/adapter/src/utils/useLocale.test.js @@ -1,6 +1,6 @@ import { useDataQuery } from '@dhis2/app-runtime' import i18n from '@dhis2/d2-i18n' -import { renderHook } from '@testing-library/react-hooks' +import { renderHook, waitFor } from '@testing-library/react' import moment from 'moment' import { useCurrentUserLocale } from './useLocale.js' @@ -84,7 +84,7 @@ describe('formerly problematic locales', () => { useDataQuery.mockReturnValue({ data: { userSettings: { keyUiLocale: 'pt_BR' } }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('ltr') // Notice different locale formats @@ -109,7 +109,7 @@ describe('formerly problematic locales', () => { useDataQuery.mockReturnValue({ data: { userSettings: { keyUiLocale: 'ar_EG' } }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('rtl') expect(result.current.locale.baseName).toBe('ar-EG') @@ -127,7 +127,7 @@ describe('formerly problematic locales', () => { useDataQuery.mockReturnValue({ data: { userSettings: { keyUiLocale: 'uz_UZ_Cyrl' } }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('ltr') expect(result.current.locale.baseName).toBe('uz-Cyrl-UZ') @@ -141,7 +141,7 @@ describe('formerly problematic locales', () => { useDataQuery.mockReturnValue({ data: { userSettings: { keyUiLocale: 'uz_UZ_Latn' } }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('ltr') expect(result.current.locale.baseName).toBe('uz-Latn-UZ') @@ -166,7 +166,7 @@ describe('other userSettings cases', () => { userSettings: { keyUiLocale: 'en', keyUiLanguageTag: 'pt-BR' }, }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('ltr') expect(result.current.locale.baseName).toBe('pt-BR') @@ -180,7 +180,7 @@ describe('other userSettings cases', () => { useDataQuery.mockReturnValue({ data: { userSettings: {} }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('rtl') expect(result.current.locale.baseName).toBe('ar-EG') @@ -194,7 +194,7 @@ describe('other userSettings cases', () => { useDataQuery.mockReturnValue({ data: { userSettings: { keyUiLocale: 'shouldCauseError' } }, }) - const { result, waitFor } = renderHook(() => useCurrentUserLocale()) + const { result } = renderHook(() => useCurrentUserLocale()) expect(result.current.direction).toBe('rtl') expect(result.current.locale.baseName).toBe('ar-EG') diff --git a/cli/config/d2.pwa.config.js b/cli/config/d2.pwa.config.js deleted file mode 100644 index d9e9b0c3a..000000000 --- a/cli/config/d2.pwa.config.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Default config for PWA properties in `d2.config.js`. They are kept separate - * from other defaults so they aren't included in the `d2.config.js` created - * when a new app is initialized with `d2 app scripts init` - */ -module.exports = { - pwa: { - /** - * If true, service worker is registered to perform offline caching - * and use of cacheable sections & recording mode is enabled - */ - enabled: false, - caching: { - /** - * If true, don't cache requests to exteral domains in app shell. - * Doesn't affect recording mode - */ - omitExternalRequestsFromAppShell: false, - /** Deprecated version of above */ - omitExternalRequests: false, - /** - * Don't cache URLs matching patterns in this array in app shell. - * Doesn't affect recording mode - */ - patternsToOmitFromAppShell: [], - /** Deprecated version of above */ - patternsToOmit: [], - /** - * Don't cache URLs matching these patterns in recorded sections. - * Can still be cached in app shell unless filtered there too. - */ - patternsToOmitFromCacheableSections: [], - /** - * In addition to the contents of an app's 'build' folder, other - * URLs can be precached by adding them to this list which will - * add them to the precache manifest at build time. The format of - * this list must match the Workbox precache list format: - * https://developers.google.com/web/tools/workbox/modules/workbox-precaching#explanation_of_the_precache_list - */ - additionalManifestEntries: [], - /** - * By default, all the contents of the `build` folder are added to - * the precache to give the app the best chances of functioning - * completely while offline. Developers may choose to omit some - * of these files (for example, thousands of font or image files) - * if they cause cache bloat and the app can work fine without - * them precached. See LIBS-482 - * - * The globs should be relative to the public dir of the built app. - * Used in injectPrecacheManifest.js - */ - globsToOmitFromPrecache: [], - }, - }, -} diff --git a/cli/config/d2ConfigDefaults.js b/cli/config/d2ConfigDefaults.js new file mode 100644 index 000000000..736ce0901 --- /dev/null +++ b/cli/config/d2ConfigDefaults.js @@ -0,0 +1,25 @@ +/** + * Note that these values are different from the boilerplate files that + * are copied when using `d2-app-scripts init` -- these are used as defaults + * when parsing d2 config of existing apps + * + * The boilerplate files live in /config/init/ + */ + +const defaultsApp = { + type: 'app', + + entryPoints: { + app: './src/App.jsx', + }, +} + +const defaultsLib = { + type: 'lib', + + entryPoints: { + lib: './src/index.jsx', + }, +} + +module.exports = { defaultsApp, defaultsLib } diff --git a/cli/config/d2ConfigDefaults.typescript.js b/cli/config/d2ConfigDefaults.typescript.js new file mode 100644 index 000000000..dc21f88dc --- /dev/null +++ b/cli/config/d2ConfigDefaults.typescript.js @@ -0,0 +1,17 @@ +const defaultsApp = { + type: 'app', + + entryPoints: { + app: './src/App.tsx', + }, +} + +const defaultsLib = { + type: 'lib', + + entryPoints: { + lib: './src/index.tsx', + }, +} + +module.exports = { defaultsApp, defaultsLib } diff --git a/cli/config/jest.config.js b/cli/config/jest.config.js index a2a059a18..4277b08fe 100644 --- a/cli/config/jest.config.js +++ b/cli/config/jest.config.js @@ -3,6 +3,9 @@ module.exports = { transform: { '^.+\\.[t|j]sx?$': require.resolve('./jest.transform.js'), }, + // Need to apply babel transformations to modules under moment/dist/, + // which use ES module format. See localeUtils.js in the adapter + transformIgnorePatterns: ['/node_modules/(?!moment/dist/)'], moduleNameMapper: { '\\.(css|less)$': require.resolve('./jest.identity.mock.js'), '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': diff --git a/cli/config/makeViteConfig.mjs b/cli/config/makeViteConfig.mjs new file mode 100644 index 000000000..c393a53c8 --- /dev/null +++ b/cli/config/makeViteConfig.mjs @@ -0,0 +1,192 @@ +import react from '@vitejs/plugin-react' +import { + defineConfig, + mergeConfig, + searchForWorkspaceRoot, + transformWithEsbuild, +} from 'vite' +import dynamicImport from 'vite-plugin-dynamic-import' + +// This file is used to create config to use with the Vite Node API +// (i.e. vite.createServer() and vite.build()) +// It uses ESM format and has an .mjs extension, since the CJS build of +// Vite's Node API is deprecated and will be removed in v6 +// https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated + +/** + * Allows JSX in .js files: + * Vite normally throws an error when JSX syntax is used in a file without a + * .jsx or .tsx extension. This is by design, in order to improve transform + * performance by not parsing JS files for JSX. + * + * This plugin and the `optimizeDeps` options in this config object, + * along with the `jsxRuntime: 'classic'` option in the React plugin of the main + * config, can enable support for JSX in .js files. This config object is + * merged with the main config if the `--allowJsxInJs` flag is passed + * to the CLI + * + * ! deprecated -- this config has a performance cost, especially on startup + */ +const jsxInJsConfig = { + plugins: [ + { + name: 'treat-js-files-as-jsx', + async transform(code, id) { + if (!id.match(/src\/.*\.js$/)) { + return null + } + // Use the exposed transform from vite, instead of directly + // transforming with esbuild + return transformWithEsbuild(code, id, { + loader: 'jsx', + jsx: 'automatic', + }) + }, + }, + ], + optimizeDeps: { + force: true, + esbuildOptions: { loader: { '.js': 'jsx' } }, + }, +} + +const momentLocaleRegex = /moment\/dist\/locale\/(.*)\.js$/ +/** + * Configure chunk output a bit to make a tidier build folder: + * Assign moment locale chunks into their own dir + * (they are already individually split out due to the dynamic import + * in localeUtils.js in the adapter) + */ +const handleChunkFileNames = (info) => { + const { facadeModuleId } = info // This id is the module's filepath + return momentLocaleRegex.test(facadeModuleId) + ? 'assets/moment-locales/[name]-[hash].js' + : 'assets/[name]-[hash].js' // the Rollup default +} + +const fontRegex = /\.woff2?/ +/** Tidy up fonts in the build/assets folder */ +const handleAssetFileNames = ({ name }) => { + return fontRegex.test(name) + ? 'assets/fonts/[name]-[hash][extname]' + : 'assets/[name]-[hash][extname]' // the Rollup default +} + +/** + * Setting up static variable replacements at build time. + * Vite adds env vars (from .env files, user env, and CLI args) to + * `import.meta.env`; for backwards compatibility and generalization, we also + * add those to `process.env`. + * + * Note that variables added to `import.meta.env` here will be available in + * index.html, e.g. import.meta.env.DHIS2_APP_NAME will populate + * %DHIS2_APP_NAME% in HTML + * + * Uses individual properties for drop-in replacements instead of a whole + * object, which allows for better dead code elimination. + * + * For env vars for now, we keep the behavior in /src/lib/shell/env.js: + * loading, filtering, and prefixing env vars for CRA. + * Once we remove support for those variables, we just need: + * 1. the Shell env vars, e.g. DHIS2_APP_NAME, -_VERSION, etc. This need to + * be added to the env by the `define` configuration below + * 2. the user's env, which can be loaded and filtered by Vite's + * `vite.loadEnv(mode, process.cwd(), ['DHIS2_'])`, + * and don't need to use `define`; they just need the envPrefix config. + */ +const getDefineOptions = (env) => { + const defineOptions = {} + Object.entries(env).forEach(([key, val]) => { + // Each `val` should be a string already, but we need to stringify again + // for it to appear as a string in the resulting code: + // '"value"' here => 'value' in the code + const stringifiedVal = JSON.stringify(val) + + defineOptions[`process.env.${key}`] = stringifiedVal + // 'DHIS2_'-prefixed vars go on import.meta.env too + if (key.startsWith('DHIS2_')) { + defineOptions[`import.meta.env.${key}`] = stringifiedVal + } + }) + return defineOptions +} + +const getBuildInputs = (config, paths) => { + const inputs = {} + if (config.entryPoints.app) { + inputs.main = paths.shellIndexHtml + } + if (config.entryPoints.plugin) { + inputs.plugin = paths.shellPluginHtml + } + return inputs +} + +// https://vitejs.dev/config/ +export default ({ paths, config, env, host, force, allowJsxInJs }) => { + const baseConfig = defineConfig({ + // Need to specify the location of the app root, since this CLI command + // gets run in a different directory than the bootstrapped app + root: paths.shell, + + // By default, assets are resolved to the root of the domain ('/'), but + // deployed apps aren't served from there. + // This option is basically the same as PUBLIC_URL for CRA and Parcel. + // Works for both dev and production. + // Gets applied to import.meta.env.BASE_URL in the runtime code + base: './', + + // Expose env vars with DHIS2_ prefix in index.html and on + // import.meta.env -- process.env.REACT_APP_DHIS2_... variables should + // migrate to the import.meta.env format + // https://vitejs.dev/config/shared-options.html#envprefix + envPrefix: 'DHIS2_', + + // Static replacement of vars at build time + define: getDefineOptions(env), + + server: { + host, + // By default, Vite allows serving files from a workspace root or + // falls back to the app root. Since we run the app in .d2/shell/, + // if the app is not in a workspace, files in cwd/node_modules can + // be out of reach (like fonts, which don't get bundled). + // Start the workspace search from cwd so it falls back to that + // when not in a workspace; then fonts in node_modules are usable + // https://vitejs.dev/config/server-options.html#server-fs-allow + fs: { allow: [searchForWorkspaceRoot(process.cwd())] }, + }, + + build: { + outDir: 'build', + rollupOptions: { + input: getBuildInputs(config, paths), + output: { + chunkFileNames: handleChunkFileNames, + assetFileNames: handleAssetFileNames, + }, + }, + }, + + plugins: [ + /** + * Allows the dynamic import of `moment/dist/locale/${locale}` + * in /adapter/src/utils/localeUtils.js. + * Also works for other "bare" packages; approximates behavior of + * inline `webpackChunkName` usage. Third-party plugin. + */ + dynamicImport(), + react({ + babel: { plugins: ['styled-jsx/babel'] }, + // ! deprecated with other jsx-in-js config + // This option allows HMR of JSX-in-JS files, + // but it isn't possible to add with merge config: + jsxRuntime: allowJsxInJs ? 'classic' : 'automatic', + }), + ], + + optimizeDeps: { force }, + }) + + return allowJsxInJs ? mergeConfig(baseConfig, jsxInJsConfig) : baseConfig +} diff --git a/cli/config/plugin.webpack.config.js b/cli/config/plugin.webpack.config.js deleted file mode 100644 index 81ee88635..000000000 --- a/cli/config/plugin.webpack.config.js +++ /dev/null @@ -1,307 +0,0 @@ -// Based on CRA Webpack config - -const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') -const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') -const HtmlWebpackPlugin = require('html-webpack-plugin') -const MiniCssExtractPlugin = require('mini-css-extract-plugin') -const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent') -const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath') -const TerserPlugin = require('terser-webpack-plugin') -const webpack = require('webpack') -const WorkboxWebpackPlugin = require('workbox-webpack-plugin') -const { getPWAEnvVars } = require('../src/lib/pwa') -const getShellEnv = require('../src/lib/shell/env') -const makeBabelConfig = require('./makeBabelConfig') - -const babelWebpackConfig = { - babelrc: false, - configFile: false, - cacheDirectory: true, - cacheCompression: false, -} - -const cssRegex = /\.css$/ -const cssModuleRegex = /\.module\.css$/ - -module.exports = ({ env: webpackEnv, config, paths }) => { - const isProduction = webpackEnv === 'production' - const isDevelopment = !isProduction - - const publicPath = getPublicUrlOrPath( - isDevelopment, - null, - process.env.PUBLIC_URL - ) - - const shellEnv = getShellEnv({ - plugin: 'true', - requiredProps: config.requiredProps ? config.requiredProps.join() : '', - skipPluginLogic: config.skipPluginLogic, - name: config.title, - ...getPWAEnvVars(config), - }) - - // "style" loader turns CSS into JS modules that inject ) } diff --git a/examples/simple-app/src/Alerter.module.css b/examples/simple-app/src/Alerter.module.css new file mode 100644 index 000000000..9ff151b25 --- /dev/null +++ b/examples/simple-app/src/Alerter.module.css @@ -0,0 +1,6 @@ +.flexContainer { + display: flex; + align-items: center; + justify-content: space-between; + width: 500px; +} diff --git a/examples/simple-app/src/App.js b/examples/simple-app/src/App.jsx similarity index 68% rename from examples/simple-app/src/App.js rename to examples/simple-app/src/App.jsx index 3e1a3c037..78bf15760 100644 --- a/examples/simple-app/src/App.js +++ b/examples/simple-app/src/App.jsx @@ -1,8 +1,8 @@ import { useDataQuery } from '@dhis2/app-runtime' import moment from 'moment' import React from 'react' -import { Alerter } from './Alerter.js' -import style from './App.style.js' +import { Alerter } from './Alerter.jsx' +import styles from './App.module.css' import i18n from './locales/index.js' const query = { @@ -14,8 +14,7 @@ const query = { const Component = () => { const { error, loading, data } = useDataQuery(query) return ( -