@jsenv/plugin-preact 0.0.1

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.
package/index.js ADDED
@@ -0,0 +1 @@
1
+ export { jsenvPluginPreact } from "./src/jsenv_plugin_preact.js"
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@jsenv/plugin-preact",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/jsenv/jsenv-core",
8
+ "directory": "packages/node-esm-resolution"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public",
12
+ "registry": "https://registry.npmjs.org"
13
+ },
14
+ "type": "module",
15
+ "dependencies": {
16
+ "@babel/plugin-transform-react-jsx": "7.17.3",
17
+ "@jsenv/utils": "1.0.0",
18
+ "@jsenv/url-meta": "6.2.0"
19
+ },
20
+ "devDependencies": {
21
+ "@babel/plugin-transform-react-jsx-development": "7.16.7",
22
+ "@prefresh/babel-plugin": "0.4.3",
23
+ "@prefresh/core": "1.3.4",
24
+ "@prefresh/utils": "1.1.3",
25
+ "babel-plugin-transform-hook-names": "1.0.2"
26
+ }
27
+ }
@@ -0,0 +1,36 @@
1
+ /* globals self */
2
+
3
+ import "@prefresh/core"
4
+ import { flush } from "@prefresh/utils"
5
+
6
+ export const installPrefresh = (url) => {
7
+ let prevRefreshReg = self.$RefreshReg$ || (() => {})
8
+ let prevRefreshSig = self.$RefreshSig$ || (() => (type) => type)
9
+ self.$RefreshReg$ = (type, id) => {
10
+ self.__PREFRESH__.register(type, `${url} ${id}`)
11
+ }
12
+ self.$RefreshSig$ = () => {
13
+ let status = "begin"
14
+ let savedType
15
+ return (type, key, forceReset, getCustomHooks) => {
16
+ if (!savedType) savedType = type
17
+ status = self.__PREFRESH__.sign(
18
+ type || savedType,
19
+ key,
20
+ forceReset,
21
+ getCustomHooks,
22
+ status,
23
+ )
24
+ return type
25
+ }
26
+ }
27
+ return {
28
+ end: () => {
29
+ self.$RefreshReg$ = prevRefreshReg
30
+ self.$RefreshSig$ = prevRefreshSig
31
+ },
32
+ acceptCallback: () => {
33
+ flush()
34
+ },
35
+ }
36
+ }
@@ -0,0 +1,174 @@
1
+ /*
2
+ * - https://github.com/preactjs/preset-vite/blob/main/src/index.ts
3
+ * - https://github.com/preactjs/prefresh/blob/main/packages/vite/src/index.js
4
+ */
5
+
6
+ import { normalizeStructuredMetaMap, urlToMeta } from "@jsenv/url-meta"
7
+
8
+ import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
9
+ import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
10
+ import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_composition_v3.js"
11
+ import {
12
+ parseHtmlString,
13
+ stringifyHtmlAst,
14
+ injectScriptAsEarlyAsPossible,
15
+ createHtmlNode,
16
+ } from "@jsenv/utils/html_ast/html_ast.js"
17
+
18
+ export const jsenvPluginPreact = ({
19
+ hotRefreshPatterns = {
20
+ "./**/*.jsx": true,
21
+ "./**/*.tsx": true,
22
+ "./**/node_modules/": false,
23
+ },
24
+ preactDevtoolsDuringBuild = false,
25
+ } = {}) => {
26
+ const structuredMetaMap = normalizeStructuredMetaMap(
27
+ {
28
+ hot: hotRefreshPatterns,
29
+ },
30
+ "file://",
31
+ )
32
+ const shouldEnablePrefresh = (url) => {
33
+ return urlToMeta({ url, structuredMetaMap }).hot
34
+ }
35
+
36
+ return {
37
+ name: "jsenv:preact",
38
+ appliesDuring: "*",
39
+ resolve: {
40
+ js_import_export: (reference, { resolveReference }) => {
41
+ if (
42
+ reference.specifier === "react" ||
43
+ reference.specifier === "react-dom"
44
+ ) {
45
+ reference.specifier = "preact/compat"
46
+ return resolveReference(reference).url
47
+ }
48
+ return null
49
+ },
50
+ },
51
+ transform: {
52
+ html: ({ content }, { scenario, referenceUtils }) => {
53
+ if (!preactDevtoolsDuringBuild && scenario === "build") {
54
+ return null
55
+ }
56
+ const htmlAst = parseHtmlString(content)
57
+ const [preactDevtoolsReference] = referenceUtils.inject({
58
+ type: "js_import_export",
59
+ specifier:
60
+ scenario === "dev" || scenario === "test"
61
+ ? "preact/debug"
62
+ : "preact/devtools",
63
+ })
64
+ injectScriptAsEarlyAsPossible(
65
+ htmlAst,
66
+ createHtmlNode({
67
+ "tagName": "script",
68
+ "type": "module",
69
+ "textContent": `
70
+ import ${preactDevtoolsReference.generatedSpecifier}
71
+ `,
72
+ "injected-by": "jsenv:preact",
73
+ }),
74
+ )
75
+ const htmlModified = stringifyHtmlAst(htmlAst)
76
+ return { content: htmlModified }
77
+ },
78
+ js_module: async (
79
+ { url, generatedUrl, content },
80
+ { scenario, referenceUtils },
81
+ ) => {
82
+ // case "Fragment":
83
+ // return `${source}/${development ? "jsx-dev-runtime" : "jsx-runtime"}`;
84
+ // case "jsxDEV":
85
+ // return `${source}/jsx-dev-runtime`;
86
+ // case "jsx":
87
+ // case "jsxs":
88
+ // return `${source}/jsx-runtime`;
89
+ // case "createElement":
90
+ // return source;
91
+ const prefreshEnabled =
92
+ scenario === "dev" ? shouldEnablePrefresh(url) : false
93
+ const hookNamesEnabled = scenario === "dev"
94
+ const { code, map } = await applyBabelPlugins({
95
+ babelPlugins: [
96
+ [
97
+ scenario === "dev"
98
+ ? "@babel/plugin-transform-react-jsx-development"
99
+ : "@babel/plugin-transform-react-jsx",
100
+ {
101
+ runtime: "automatic",
102
+ importSource: "preact",
103
+ },
104
+ ],
105
+ ...(hookNamesEnabled ? ["babel-plugin-transform-hook-names"] : []),
106
+ ...(prefreshEnabled ? ["@prefresh/babel-plugin"] : []),
107
+ ],
108
+ url,
109
+ generatedUrl,
110
+ content,
111
+ })
112
+ const magicSource = createMagicSource(code)
113
+ // When a plugin wants to inject import, it must use "generatedSpecifier" returned by "addReference":
114
+ // const preactJsxRuntimeReference = addReference({
115
+ // type: "js_import_export",
116
+ // specifier: "preact/jsx-runtime"
117
+ // })
118
+ // console.log(preactJsxRuntimeReference.generatedSpecifier)
119
+ // -> "/node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js"
120
+ // Here "@babel/plugin-transform-react-jsx" is injecting some of these 3 imports into the code:
121
+ // 1. import { jsx } from "preact/jsx-runtime"
122
+ // 2. import { jsxDev } from "preact/jsx-dev-runtime"
123
+ // 3. import { createElement } from "preact"
124
+ // see https://github.com/babel/babel/blob/410c9acf1b9212cac69d50b5bb2015b9f372acc4/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts#L743-L755
125
+ // "@babel/plugin-transform-react-jsx" cannot be configured to inject
126
+ // "/node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js" instead of "preact/jsx-runtime"
127
+ // But that's fine we can still replace these imports afterwards as done below
128
+ const injectedSpecifiers = [
129
+ `"preact"`,
130
+ `"preact/jsx-dev-runtime"`,
131
+ `"preact/jsx-runtime"`,
132
+ ]
133
+ for (const importSpecifier of injectedSpecifiers) {
134
+ const index = code.indexOf(importSpecifier)
135
+ if (index > -1) {
136
+ magicSource.replace({
137
+ start: index,
138
+ end: index + importSpecifier.length,
139
+ replacement: referenceUtils.inject({
140
+ type: "js_import_export",
141
+ specifier: importSpecifier.slice(1, -1),
142
+ }).generatedSpecifier,
143
+ })
144
+ }
145
+ }
146
+ if (prefreshEnabled) {
147
+ const hasReg = /\$RefreshReg\$\(/.test(code)
148
+ const hasSig = /\$RefreshSig\$\(/.test(code)
149
+ if (hasReg || hasSig) {
150
+ const prefreshClientFileReference = referenceUtils.inject({
151
+ type: "js_import_export",
152
+ specifier: "@jsenv/plugin-preact/src/client/prefresh.js",
153
+ })
154
+ magicSource.prepend(`import { installPrefresh } from ${
155
+ prefreshClientFileReference.generatedSpecifier
156
+ }
157
+ const __prefresh__ = installPrefresh(${JSON.stringify(url)})
158
+ `)
159
+ if (hasReg) {
160
+ magicSource.append(`
161
+ __prefresh__.end()
162
+ import.meta.hot.accept(__prefresh__.acceptCallback)`)
163
+ }
164
+ }
165
+ }
166
+ const result = magicSource.toContentAndSourcemap()
167
+ return {
168
+ content: result.content,
169
+ sourcemap: await composeTwoSourcemaps(map, result.sourcemap),
170
+ }
171
+ },
172
+ },
173
+ }
174
+ }