superglue 2.0.0.alpha.10 → 2.0.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/channels/superglue/streams/broadcasts.rb +4 -34
  3. data/app/helpers/superglue/streams_helper.rb +2 -2
  4. data/app/models/concerns/superglue/broadcastable.rb +10 -36
  5. data/lib/generators/superglue/install/install_generator.rb +193 -25
  6. data/lib/generators/superglue/install/templates/application.json.props +1 -3
  7. data/lib/generators/superglue/install/templates/bun/bun.config.deepkit.js +38 -0
  8. data/lib/generators/superglue/install/templates/bun/bun.config.js +34 -0
  9. data/lib/generators/superglue/install/templates/bun/bun.config.ts.js +34 -0
  10. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.js +10 -0
  11. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.ts +10 -0
  12. data/lib/generators/superglue/install/templates/js/application.jsx +24 -18
  13. data/lib/generators/superglue/install/templates/js/application_visit.js +31 -61
  14. data/lib/generators/superglue/install/templates/js/build.mjs +26 -0
  15. data/lib/generators/superglue/install/templates/js/flash.js +6 -47
  16. data/lib/generators/superglue/install/templates/js/layout.jsx +2 -2
  17. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.js +9 -0
  18. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.ts +9 -0
  19. data/lib/generators/superglue/install/templates/rollup/rollup.config.deepkit.js +37 -0
  20. data/lib/generators/superglue/install/templates/rollup/rollup.config.js +32 -0
  21. data/lib/generators/superglue/install/templates/rollup/rollup.config.ts.js +35 -0
  22. data/lib/generators/superglue/install/templates/stream.json.props +1 -3
  23. data/lib/generators/superglue/install/templates/ts/application.tsx +24 -18
  24. data/lib/generators/superglue/install/templates/ts/application_visit.ts +35 -64
  25. data/lib/generators/superglue/install/templates/ts/build.deepkit.mjs +27 -0
  26. data/lib/generators/superglue/install/templates/ts/build.mjs +26 -0
  27. data/lib/generators/superglue/install/templates/ts/flash.ts +16 -48
  28. data/lib/generators/superglue/install/templates/ts/layout.tsx +2 -2
  29. data/lib/generators/superglue/install/templates/ts/page_to_page_mapping.ts +3 -1
  30. data/lib/generators/superglue/install/templates/ts/tsconfig.json +2 -2
  31. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.js +9 -0
  32. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.ts +9 -0
  33. data/lib/generators/superglue/install/templates/webpack/webpack.config.deepkit.js +42 -0
  34. data/lib/generators/superglue/install/templates/webpack/webpack.config.js +40 -0
  35. data/lib/generators/superglue/install/templates/webpack/webpack.config.ts.js +40 -0
  36. data/lib/generators/superglue/view_collection/templates/js/edit.jsx +7 -6
  37. data/lib/generators/superglue/view_collection/templates/js/new.jsx +9 -8
  38. data/lib/generators/superglue/view_collection/templates/ts/edit.tsx +9 -8
  39. data/lib/generators/superglue/view_collection/templates/ts/new.tsx +10 -9
  40. data/lib/superglue/engine.rb +0 -1
  41. data/lib/superglue/rendering.rb +18 -4
  42. data/lib/superglue.rb +0 -10
  43. metadata +21 -8
  44. data/app/controllers/concerns/superglue/request_id_tracking.rb +0 -16
  45. data/app/models/superglue/debouncer.rb +0 -28
  46. data/app/models/superglue/thread_debouncer.rb +0 -30
  47. data/lib/generators/superglue/install/templates/js/store.js +0 -31
  48. data/lib/generators/superglue/install/templates/ts/store.ts +0 -35
@@ -1,5 +1,3 @@
1
- import { visit, remote } from "@thoughtbot/superglue/action_creators"
2
-
3
1
  /**
4
2
  * This function returns a wrapped visit and remote that will be used by UJS,
5
3
  * the Navigation component, and passed to your page components through the
@@ -8,7 +6,7 @@ import { visit, remote } from "@thoughtbot/superglue/action_creators"
8
6
  * You can customize both functions to your liking. For example, for a progress
9
7
  * bar. This file also adds support for data-sg-remote.
10
8
  */
11
- export const buildVisitAndRemote = (ref, store) => {
9
+ export const buildVisitAndRemote = ({ navigateTo, visit, remote }) => {
12
10
  const appRemote = (path, { dataset, ...options } = {}) => {
13
11
  /**
14
12
  * You can make use of `dataset` to add custom UJS options.
@@ -23,27 +21,38 @@ export const buildVisitAndRemote = (ref, store) => {
23
21
  *
24
22
  * This would be available as `sgHideProgress` on the dataset
25
23
  */
26
- return store.dispatch(remote(path, options))
24
+ return remote(path, options).then(result => {
25
+ if (result.hasError) {
26
+ const { response } = result
27
+
28
+ if (response.status >= 400 && response.status < 500) {
29
+ window.location.href = "/400.html"
30
+ } else if (response.status >= 500) {
31
+ window.location.href = "/500.html"
32
+ }
33
+ }
34
+
35
+ return result
36
+ })
27
37
  }
28
38
 
29
39
  const appVisit = (path, { dataset, ...options } = {}) => {
30
40
  /**
31
41
  * Do something before we make a request.
32
42
  * e.g, show a [progress bar](https://thoughtbot.github.io/superglue/recipes/progress-bar/).
33
- *
34
- * Hint: you can access the current pageKey
35
- * via `store.getState().superglue.currentPageKey`
36
43
  */
37
- return store
38
- .dispatch(visit(path, options))
39
- .then(meta => {
40
- /**
41
- * The assets fingerprints changed, instead of transitioning
42
- * just go to the URL directly to retrieve new assets
43
- */
44
- if (meta.needsRefresh) {
45
- window.location.href = meta.pageKey
46
- return meta
44
+ return visit(path, options)
45
+ .then(result => {
46
+ if (result.hasError) {
47
+ const { response } = result
48
+
49
+ if (response.status >= 400 && response.status < 500) {
50
+ window.location.href = "/400.html"
51
+ } else if (response.status >= 500) {
52
+ window.location.href = "/500.html"
53
+ }
54
+
55
+ return result
47
56
  }
48
57
 
49
58
  /**
@@ -52,19 +61,14 @@ export const buildVisitAndRemote = (ref, store) => {
52
61
  * This option overrides the `navigationAction` to allow a link click or
53
62
  * a form submission to replace history instead of the usual push.
54
63
  */
55
- const navigatonAction = !!dataset?.sgReplace
64
+ const navigationAction = !!dataset?.sgReplace
56
65
  ? "replace"
57
- : meta.navigationAction
58
- ref.current?.navigateTo(meta.pageKey, {
59
- action: navigatonAction
66
+ : result.navigationAction
67
+ navigateTo(result.pageKey, {
68
+ action: navigationAction
60
69
  })
61
70
 
62
- /**
63
- * Return the meta object, it's used for scroll restoration when
64
- * handling the back button. You can skip returning, but Superglue
65
- * will warn you about scroll restoration.
66
- */
67
- return meta
71
+ return result
68
72
  })
69
73
  .finally(() => {
70
74
  /**
@@ -73,40 +77,6 @@ export const buildVisitAndRemote = (ref, store) => {
73
77
  * This is where you hide a progress bar.
74
78
  */
75
79
  })
76
- .catch(err => {
77
- const response = err.response
78
-
79
- if (!response) {
80
- /**
81
- * This is for errors that are NOT from a HTTP request.
82
- *
83
- * Tooling like Sentry can capture console errors. If not, feel
84
- * free to customize to send the error to your telemetry tool of choice.
85
- */
86
- console.error(err)
87
- return
88
- }
89
-
90
- if (response.ok) {
91
- /**
92
- * This is for errors that are from a HTTP request.
93
- *
94
- * If the response is OK, it must be an HTML body, we'll
95
- * go to that locaton directly.
96
- */
97
- window.location = response.url
98
- } else {
99
- if (response.status >= 400 && response.status < 500) {
100
- window.location.href = "/400.html"
101
- return
102
- }
103
-
104
- if (response.status >= 500) {
105
- window.location.href = "/500.html"
106
- return
107
- }
108
- }
109
- })
110
80
  }
111
81
 
112
82
  return { visit: appVisit, remote: appRemote }
@@ -0,0 +1,26 @@
1
+ import * as esbuild from 'esbuild'
2
+
3
+ const isWatch = process.argv.includes('--watch')
4
+
5
+ const buildOptions = {
6
+ entryPoints: [
7
+ 'app/javascript/application.jsx',
8
+ ],
9
+ bundle: true,
10
+ sourcemap: true,
11
+ format: 'esm',
12
+ outdir: 'app/assets/builds',
13
+ publicPath: '/assets',
14
+ plugins: process.env.NODE_ENV === 'production' ? [] : [] ,
15
+ metafile: true,
16
+ conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
17
+ }
18
+
19
+ if (isWatch) {
20
+ const ctx = await esbuild.context(buildOptions)
21
+ await ctx.watch()
22
+ console.log('Watching for changes...')
23
+ } else {
24
+ const result = await esbuild.build(buildOptions)
25
+ console.log(await esbuild.analyzeMetafile(result.metafile))
26
+ }
@@ -1,48 +1,7 @@
1
- import { createSlice } from "@reduxjs/toolkit"
2
- import { receiveResponse , beforeVisit } from "@thoughtbot/superglue"
1
+ import { useFlash } from "@thoughtbot/superglue"
3
2
 
4
- const initialState = {}
5
-
6
- export const flashSlice = createSlice({
7
- name: "flash",
8
- initialState: initialState,
9
- reducers: {
10
- clearFlash(state, { payload }) {
11
- const key = payload
12
- if (!key) {
13
- return {}
14
- }
15
-
16
- delete state[key]
17
-
18
- return {
19
- ...state
20
- }
21
- },
22
- flash(state, { payload }) {
23
- return {
24
- ...state,
25
- ...payload
26
- }
27
- }
28
- },
29
- extraReducers: builder => {
30
- builder.addCase(beforeVisit, (_state, _action) => {
31
- return {}
32
- })
33
- builder.addCase(receiveResponse , (state, action) => {
34
- const { response } = action.payload
35
-
36
- if(response.slices) {
37
- return {
38
- ...state,
39
- ...response.slices.flash
40
- }
41
- } else {
42
- return state
43
- }
44
- })
45
- }
46
- })
47
-
48
- export const { clearFlash, flash } = flashSlice.actions
3
+ /**
4
+ * A typed wrapper around useFlash. Customize the return shape
5
+ * to match the flash keys your application uses.
6
+ */
7
+ export const useAppFlash = () => useFlash()
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
- import { useSelector } from 'react-redux'
2
+ import { useAppFlash } from '@javascript/flash'
3
3
 
4
4
  export const Layout = ({children}) => {
5
- const flash = useSelector((state) => state.flash)
5
+ const flash = useAppFlash()
6
6
 
7
7
  return (
8
8
  <div>
@@ -0,0 +1,9 @@
1
+ const pageIdentifierToPageComponent = {}
2
+ const pages = import.meta.glob('../views/**/*.jsx', { eager: true })
3
+
4
+ for (const key in pages) {
5
+ const identifier = key.replace('../views/', '').split('.')[0]
6
+ pageIdentifierToPageComponent[identifier] = pages[key].default
7
+ }
8
+
9
+ export { pageIdentifierToPageComponent }
@@ -0,0 +1,9 @@
1
+ const pageIdentifierToPageComponent: Record<string, React.ComponentType> = {}
2
+ const pages = import.meta.glob('../views/**/*.tsx', { eager: true })
3
+
4
+ for (const key in pages) {
5
+ const identifier = key.replace('../views/', '').split('.')[0]
6
+ pageIdentifierToPageComponent[identifier] = (pages[key] as { default: React.ComponentType }).default
7
+ }
8
+
9
+ export { pageIdentifierToPageComponent }
@@ -0,0 +1,37 @@
1
+ import path from "path"
2
+ import resolve from "@rollup/plugin-node-resolve"
3
+ import commonjs from "@rollup/plugin-commonjs"
4
+ import babel from "@rollup/plugin-babel"
5
+ import alias from "@rollup/plugin-alias"
6
+ import importMetaGlob from "rollup-plugin-import-meta-glob"
7
+ import { rollup as deepkitPlugin } from "@thoughtbot/superglue/deepkit"
8
+
9
+ export default {
10
+ input: "app/javascript/application.tsx",
11
+ output: {
12
+ file: "app/assets/builds/application.js",
13
+ format: "esm",
14
+ inlineDynamicImports: true,
15
+ sourcemap: true
16
+ },
17
+ plugins: [
18
+ importMetaGlob(),
19
+ alias({
20
+ entries: [
21
+ { find: "@javascript", replacement: path.resolve("app/javascript") },
22
+ { find: "@views", replacement: path.resolve("app/views") }
23
+ ]
24
+ }),
25
+ resolve({ extensions: [".ts", ".tsx", ".js", ".jsx"] }),
26
+ commonjs(),
27
+ babel({
28
+ babelHelpers: "bundled",
29
+ presets: [
30
+ ["@babel/preset-react", { runtime: "automatic" }],
31
+ "@babel/preset-typescript"
32
+ ],
33
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
34
+ }),
35
+ ...(process.env.NODE_ENV === 'production' ? [] : [deepkitPlugin()])
36
+ ]
37
+ }
@@ -0,0 +1,32 @@
1
+ import path from "path"
2
+ import resolve from "@rollup/plugin-node-resolve"
3
+ import commonjs from "@rollup/plugin-commonjs"
4
+ import babel from "@rollup/plugin-babel"
5
+ import alias from "@rollup/plugin-alias"
6
+ import importMetaGlob from "rollup-plugin-import-meta-glob"
7
+
8
+ export default {
9
+ input: "app/javascript/application.jsx",
10
+ output: {
11
+ file: "app/assets/builds/application.js",
12
+ format: "esm",
13
+ inlineDynamicImports: true,
14
+ sourcemap: true
15
+ },
16
+ plugins: [
17
+ importMetaGlob(),
18
+ alias({
19
+ entries: [
20
+ { find: "@javascript", replacement: path.resolve("app/javascript") },
21
+ { find: "@views", replacement: path.resolve("app/views") }
22
+ ]
23
+ }),
24
+ resolve({ extensions: [".js", ".jsx"] }),
25
+ commonjs(),
26
+ babel({
27
+ babelHelpers: "bundled",
28
+ presets: [["@babel/preset-react", { runtime: "automatic" }]],
29
+ extensions: [".js", ".jsx"]
30
+ })
31
+ ]
32
+ }
@@ -0,0 +1,35 @@
1
+ import path from "path"
2
+ import resolve from "@rollup/plugin-node-resolve"
3
+ import commonjs from "@rollup/plugin-commonjs"
4
+ import babel from "@rollup/plugin-babel"
5
+ import alias from "@rollup/plugin-alias"
6
+ import importMetaGlob from "rollup-plugin-import-meta-glob"
7
+
8
+ export default {
9
+ input: "app/javascript/application.tsx",
10
+ output: {
11
+ file: "app/assets/builds/application.js",
12
+ format: "esm",
13
+ inlineDynamicImports: true,
14
+ sourcemap: true
15
+ },
16
+ plugins: [
17
+ importMetaGlob(),
18
+ alias({
19
+ entries: [
20
+ { find: "@javascript", replacement: path.resolve("app/javascript") },
21
+ { find: "@views", replacement: path.resolve("app/views") }
22
+ ]
23
+ }),
24
+ resolve({ extensions: [".ts", ".tsx", ".js", ".jsx"] }),
25
+ commonjs(),
26
+ babel({
27
+ babelHelpers: "bundled",
28
+ presets: [
29
+ ["@babel/preset-react", { runtime: "automatic" }],
30
+ "@babel/preset-typescript"
31
+ ],
32
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
33
+ })
34
+ ]
35
+ }
@@ -14,6 +14,4 @@ end
14
14
 
15
15
  json.action "handleStreamResponse"
16
16
 
17
- json.slices do
18
- json.flash flash.to_h
19
- end
17
+ json.flash flash.to_h
@@ -1,9 +1,9 @@
1
1
  import React from "react";
2
2
  import { createRoot } from "react-dom/client";
3
- import { Application, SaveResponse } from "@thoughtbot/superglue";
3
+ import { createApp, SaveResponse } from "@thoughtbot/superglue";
4
4
  import { buildVisitAndRemote } from "./application_visit";
5
5
  import { pageIdentifierToPageComponent } from "./page_to_page_mapping";
6
- import { store } from "./store";
6
+ import { Layout } from "./components";
7
7
 
8
8
  declare global {
9
9
  interface Window {
@@ -17,24 +17,30 @@ if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
17
17
  const location = window.location;
18
18
 
19
19
  if (appEl) {
20
+ const { Provider, Outlet, ujs } = createApp({
21
+ // The base url prefixed to all calls made by the `visit`
22
+ // and `remote` thunks.
23
+ baseUrl: location.origin,
24
+ // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
25
+ // template, e.g., index.html.erb
26
+ initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
27
+ // The initial path of the page, e.g., /foobar
28
+ path: location.pathname + location.search + location.hash,
29
+ // Callback used to setup visit and remote
30
+ buildVisitAndRemote,
31
+ // Mapping between the page identifier to page component
32
+ mapping: pageIdentifierToPageComponent,
33
+ });
34
+
20
35
  const root = createRoot(appEl);
21
36
  root.render(
22
- <Application
23
- // The base url prefixed to all calls made by the `visit`
24
- // and `remote` thunks.
25
- baseUrl={location.origin}
26
- // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
27
- // template, e.g., index.html.erb
28
- initialPage={window.SUPERGLUE_INITIAL_PAGE_STATE}
29
- // The initial path of the page, e.g., /foobar
30
- path={location.pathname + location.search + location.hash}
31
- // Callback used to setup visit and remote
32
- buildVisitAndRemote={buildVisitAndRemote}
33
- // Callback used to setup the store
34
- store={store}
35
- // Mapping between the page identifier to page component
36
- mapping={pageIdentifierToPageComponent}
37
- />
37
+ <div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
38
+ <Provider>
39
+ <Layout>
40
+ <Outlet />
41
+ </Layout>
42
+ </Provider>
43
+ </div>
38
44
  );
39
45
  }
40
46
  });
@@ -1,10 +1,8 @@
1
1
  import {
2
2
  ApplicationRemote,
3
3
  ApplicationVisit,
4
- SuperglueStore,
5
4
  BuildVisitAndRemote,
6
5
  } from "@thoughtbot/superglue";
7
- import { visit, remote } from "@thoughtbot/superglue/action_creators";
8
6
 
9
7
  /**
10
8
  * This function returns a wrapped visit and remote that will be used by UJS,
@@ -14,10 +12,11 @@ import { visit, remote } from "@thoughtbot/superglue/action_creators";
14
12
  * You can customize both functions to your liking. For example, for a progress
15
13
  * bar. This file also adds support for data-sg-remote.
16
14
  */
17
- export const buildVisitAndRemote: BuildVisitAndRemote = (
18
- ref,
19
- store: SuperglueStore
20
- ) => {
15
+ export const buildVisitAndRemote: BuildVisitAndRemote = ({
16
+ navigateTo,
17
+ visit,
18
+ remote,
19
+ }) => {
21
20
  const appRemote: ApplicationRemote = (path, { dataset, ...options } = {}) => {
22
21
  /**
23
22
  * You can make use of `dataset` to add custom UJS options.
@@ -32,27 +31,38 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
32
31
  *
33
32
  * This would be available as `sgHideProgress` on the dataset
34
33
  */
35
- return store.dispatch(remote(path, options));
34
+ return remote(path, options).then((result) => {
35
+ if (result.hasError) {
36
+ const { response } = result;
37
+
38
+ if (response.status >= 400 && response.status < 500) {
39
+ window.location.href = "/400.html";
40
+ } else if (response.status >= 500) {
41
+ window.location.href = "/500.html";
42
+ }
43
+ }
44
+
45
+ return result;
46
+ });
36
47
  };
37
48
 
38
49
  const appVisit: ApplicationVisit = (path, { dataset, ...options } = {}) => {
39
50
  /**
40
51
  * Do something before we make a request.
41
52
  * e.g, show a [progress bar](https://thoughtbot.github.io/superglue/recipes/progress-bar/).
42
- *
43
- * Hint: you can access the current pageKey
44
- * via `store.getState().superglue.currentPageKey`
45
53
  */
46
- return store
47
- .dispatch(visit(path, options))
48
- .then((meta) => {
49
- /**
50
- * The assets fingerprints changed, instead of transitioning
51
- * just go to the URL directly to retrieve new assets
52
- */
53
- if (meta.needsRefresh) {
54
- window.location.href = meta.pageKey;
55
- return meta;
54
+ return visit(path, options)
55
+ .then((result) => {
56
+ if (result.hasError) {
57
+ const { response } = result;
58
+
59
+ if (response.status >= 400 && response.status < 500) {
60
+ window.location.href = "/400.html";
61
+ } else if (response.status >= 500) {
62
+ window.location.href = "/500.html";
63
+ }
64
+
65
+ return result;
56
66
  }
57
67
 
58
68
  /**
@@ -61,19 +71,14 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
61
71
  * This option overrides the `navigationAction` to allow a link click or
62
72
  * a form submission to replace history instead of the usual push.
63
73
  */
64
- const navigatonAction = !!dataset?.sgReplace
74
+ const navigationAction = !!dataset?.sgReplace
65
75
  ? "replace"
66
- : meta.navigationAction;
67
- ref.current?.navigateTo(meta.pageKey, {
68
- action: navigatonAction,
76
+ : result.navigationAction;
77
+ navigateTo(result.pageKey, {
78
+ action: navigationAction,
69
79
  });
70
80
 
71
- /**
72
- * Return the meta object, it's used for scroll restoration when
73
- * handling the back button. You can skip returning, but Superglue
74
- * will warn you about scroll restoration.
75
- */
76
- return meta;
81
+ return result;
77
82
  })
78
83
  .finally(() => {
79
84
  /**
@@ -81,40 +86,6 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
81
86
  *
82
87
  * This is where you hide a progress bar.
83
88
  */
84
- })
85
- .catch((err) => {
86
- const response = err.response;
87
-
88
- if (!response) {
89
- /**
90
- * This is for errors that are NOT from a HTTP request.
91
- *
92
- * Tooling like Sentry can capture console errors. If not, feel
93
- * free to customize to send the error to your telemetry tool of choice.
94
- */
95
- console.error(err);
96
- return;
97
- }
98
-
99
- if (response.ok) {
100
- /**
101
- * This is for errors that are from a HTTP request.
102
- *
103
- * If the response is OK, it must be an HTML body, we'll
104
- * go to that locaton directly.
105
- */
106
- window.location = response.url;
107
- } else {
108
- if (response.status >= 400 && response.status < 500) {
109
- window.location.href = "/400.html";
110
- return;
111
- }
112
-
113
- if (response.status >= 500) {
114
- window.location.href = "/500.html";
115
- return;
116
- }
117
- }
118
89
  });
119
90
  };
120
91
 
@@ -0,0 +1,27 @@
1
+ import * as esbuild from 'esbuild'
2
+ import { esbuild as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
3
+
4
+ const isWatch = process.argv.includes('--watch')
5
+
6
+ const buildOptions = {
7
+ entryPoints: [
8
+ 'app/javascript/application.tsx',
9
+ ],
10
+ bundle: true,
11
+ sourcemap: true,
12
+ format: 'esm',
13
+ outdir: 'app/assets/builds',
14
+ publicPath: '/assets',
15
+ plugins: process.env.NODE_ENV === 'production' ? [] : [deepkitPlugin()],
16
+ metafile: true,
17
+ conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
18
+ }
19
+
20
+ if (isWatch) {
21
+ const ctx = await esbuild.context(buildOptions)
22
+ await ctx.watch()
23
+ console.log('Watching for changes...')
24
+ } else {
25
+ const result = await esbuild.build(buildOptions)
26
+ console.log(await esbuild.analyzeMetafile(result.metafile))
27
+ }
@@ -0,0 +1,26 @@
1
+ import * as esbuild from 'esbuild'
2
+
3
+ const isWatch = process.argv.includes('--watch')
4
+
5
+ const buildOptions = {
6
+ entryPoints: [
7
+ 'app/javascript/application.tsx',
8
+ ],
9
+ bundle: true,
10
+ sourcemap: true,
11
+ format: 'esm',
12
+ outdir: 'app/assets/builds',
13
+ publicPath: '/assets',
14
+ plugins: [],
15
+ metafile: true,
16
+ conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
17
+ }
18
+
19
+ if (isWatch) {
20
+ const ctx = await esbuild.context(buildOptions)
21
+ await ctx.watch()
22
+ console.log('Watching for changes...')
23
+ } else {
24
+ const result = await esbuild.build(buildOptions)
25
+ console.log(await esbuild.analyzeMetafile(result.metafile))
26
+ }