Skip to content

Commit

Permalink
feat: handle plugins with Vite [LIBS-610] (#863)
Browse files Browse the repository at this point in the history
* chore: update yarn.lock

* refactor: use Vite Node API for starting apps

* chore: extend gitignore

* feat: use Vite Node API to build apps

* feat: build & serve plugins with Vite

* chore: clean up unused "start app or plugin" logic

* chore: clean up old plugin code (yay!)

* chore: update pwa example app to jsx extensions

* chore: one more JSX

* feat: make building apps and plugins independent

* chore: update vite dependency location

* fix(deploy): support deploying plugins without an app

* chore: comment

* fix: default config type

* fix: solve clunky exit from start script with ctrl-C

* fix: handle undefined defaults

* fix: leaner caching in dev (wip)

* fix: handling 400+ & 500+ responses

* refactor: move strategies to new file

* fix: dev caching strategy

* refactor: inject `isPlugin` var at bootstrap time

* chore: delete unused static vite config

* chore: performance cost comment

* fix: print build error

* chore: comment

* fix: init boilerplate with .jsx extensions

* refactor: reorganize init boilerplate

* fix: smaller env for SW

* feat: improved logging

* feat: add host option to start command

* refactor: config parsing

* docs: add docs for --force option on start

* chore: improve comment
  • Loading branch information
KaiVandivier authored Jul 25, 2024
1 parent 197f58a commit ca5be0d
Show file tree
Hide file tree
Showing 45 changed files with 950 additions and 1,468 deletions.
5 changes: 3 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/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/init/entrypoint.jsx
cli/config/init/App.test.jsx
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ cli/assets

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
Expand Down
25 changes: 19 additions & 6 deletions cli/config/d2.pwa.config.js → cli/config/d2ConfigDefaults.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
/**
* 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 = {
const defaultsApp = {
type: 'app',

entryPoints: {
app: './src/App.jsx',
},
}

const defaultsLib = {
type: 'lib',

entryPoints: {
lib: './src/index.jsx',
},
}

const defaultsPWA = {
pwa: {
/**
* If true, service worker is registered to perform offline caching
Expand Down Expand Up @@ -53,3 +64,5 @@ module.exports = {
},
},
}

module.exports = { defaultsApp, defaultsLib, defaultsPWA }
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CustomDataProvider } from '@dhis2/app-runtime'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.js'
import App from './App.jsx'

it('renders without crashing', () => {
const div = document.createElement('div')
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const config = {
type: 'app',

entryPoints: {
app: './src/App.js',
app: './src/App.jsx',
},
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const config = {
type: 'lib',

entryPoints: {
lib: './src/index.js',
lib: './src/index.jsx',
},
}

Expand Down
File renamed without changes.
File renamed without changes.
96 changes: 64 additions & 32 deletions shell/vite.config.mjs → cli/config/makeViteConfig.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { resolve } from 'path'
import react from '@vitejs/plugin-react'
import { defineConfig, loadEnv, transformWithEsbuild } from 'vite'
import { defineConfig, 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
Expand All @@ -13,8 +18,9 @@ import dynamicImport from 'vite-plugin-dynamic-import'
*
* NB: State-preserving HMR will not work on React components unless they have
* a .jsx or .tsx extension though, unfortunately
*
* todo: deprecate
*
* todo: deprecate -- this and optimize deps below have a performance cost
* on startup
*/
const jsxInJSPlugin = {
name: 'treat-js-files-as-jsx',
Expand Down Expand Up @@ -54,23 +60,56 @@ const handleAssetFileNames = ({ name }) => {
: 'assets/[name]-[hash][extname]' // the Rollup default
}

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
// https://vitejs.dev/config/#using-environment-variables-in-config
const env = loadEnv(mode, process.cwd(), ['DHIS2_', 'REACT_APP_', 'NODE_ENV', 'PORT'])

// Setting up process.env replacements for backwards compatibility:
// Use individual properties for drop-in replacements instead of a whole
// object, which allows for better dead code elimination
const defineOptions = {}
Object.entries(env)
// Don't expose "just DHIS2"-prefixed env vars on process.env
.filter(([key]) => !key.startsWith('DHIS2_'))
.forEach(([key, val]) => {
/**
* Setting up static variable replacements at build time.
* Use 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 = {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
}
Object.entries(env).forEach(([key, val]) => {
// 'DHIS2_'-prefixed vars go on import.meta.env
if (key.startsWith('DHIS2_')) {
defineOptions[`import.meta.env.${key}`] = JSON.stringify(val)
return
}
// For backwards compatibility, add REACT_APP_DHIS2_... and other env
// vars to process.env. They will be statically replaced at build time.
// This will be removed in future versions
// todo: deprecate in favor of import.meta.env
defineOptions[`process.env.${key}`] = JSON.stringify(val)
})
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 }) => {
return defineConfig({
// Need to specify the location of the app root, since we're not using
// the Vite CLI from the app root
root: paths.shell,

return {
// 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.
Expand All @@ -83,23 +122,15 @@ export default defineConfig(({ mode }) => {
// https://vitejs.dev/config/shared-options.html#envprefix
envPrefix: 'DHIS2_',

// For backwards compatibility, add REACT_APP_DHIS2_... env vars
// to process.env. They will be statically replaced at build time
// This will be removed in future versions
// todo: deprecate in favor of import.meta.env
define: defineOptions,
// Static replacement of vars at build time
define: getDefineOptions(env),

// Start the server at 3000 or a configured port
server: { port: env.PORT || 3000 },
server: { host },

build: {
outDir: 'build',
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
// TODO: Dynamically build a plugin, based on context
// plugin: resolve(__dirname, 'plugin.html'),
},
input: getBuildInputs(config, paths),
output: {
chunkFileNames: handleChunkFileNames,
assetFileNames: handleAssetFileNames,
Expand All @@ -121,9 +152,10 @@ export default defineConfig(({ mode }) => {
],

// Allow JSX in .js pt. 2
// todo: deprecate - has a performance cost on startup
optimizeDeps: {
force: true,
esbuildOptions: { loader: { '.js': 'jsx' } },
},
}
})
})
}
Loading

0 comments on commit ca5be0d

Please sign in to comment.