@installgen2/vite-plugin-elm 3.1.0-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.
- package/LICENSE +57 -0
- package/README.md +121 -0
- package/dist/assetsInjector.d.ts +1 -0
- package/dist/assetsInjector.js +76 -0
- package/dist/assetsInjector.js.map +1 -0
- package/dist/compiler.d.ts +14 -0
- package/dist/compiler.js +27 -0
- package/dist/compiler.js.map +1 -0
- package/dist/compiler.test.d.ts +1 -0
- package/dist/compiler.test.js +26 -0
- package/dist/compiler.test.js.map +1 -0
- package/dist/hmrInjector.d.ts +1 -0
- package/dist/hmrInjector.js +377 -0
- package/dist/hmrInjector.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/mutex.d.ts +1 -0
- package/dist/mutex.js +26 -0
- package/dist/mutex.js.map +1 -0
- package/dist/pluginOptions.d.ts +14 -0
- package/dist/pluginOptions.js +13 -0
- package/dist/pluginOptions.js.map +1 -0
- package/dist/pluginOptions.test.d.ts +1 -0
- package/dist/pluginOptions.test.js +84 -0
- package/dist/pluginOptions.test.js.map +1 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Kengo Hamasaki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Copyright 2018 Keith Lazuka
|
|
26
|
+
|
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
28
|
+
|
|
29
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
32
|
+
|
|
33
|
+
---------------------------------------
|
|
34
|
+
|
|
35
|
+
Based on fluxxu/elm-hot-loader (https://github.com/fluxxu/elm-hot-loader)
|
|
36
|
+
|
|
37
|
+
The MIT License (MIT)
|
|
38
|
+
|
|
39
|
+
Copyright (c) 2016 Flux Xu
|
|
40
|
+
|
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
42
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
43
|
+
in the Software without restriction, including without limitation the rights
|
|
44
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
45
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
46
|
+
furnished to do so, subject to the following conditions:
|
|
47
|
+
|
|
48
|
+
The above copyright notice and this permission notice shall be included in all
|
|
49
|
+
copies or substantial portions of the Software.
|
|
50
|
+
|
|
51
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
52
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
53
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
54
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
55
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
56
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
57
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# vite-plugin-elm
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/vite-plugin-elm)
|
|
4
|
+
[](https://www.npmjs.com/package/vite-plugin-elm/v/next)
|
|
5
|
+
[](https://github.com/hmsk/vite-plugin-elm/actions/workflows/main.yml)
|
|
6
|
+
|
|
7
|
+
A plugin that enables us to compile an Elm [application](https://package.elm-lang.org/packages/elm/browser/latest/Browser#application), [document](https://package.elm-lang.org/packages/elm/browser/latest/Browser#document), or [element](https://package.elm-lang.org/packages/elm/browser/latest/Browser#element) within your [Vite](https://github.com/vitejs/vite) project. In development, [hot module replacement](https://vitejs.dev/guide/features.html#hot-module-replacement) works to some extent.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Elm } from './MyApplication.elm'
|
|
11
|
+
|
|
12
|
+
Elm.MyApplication.init()
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm i -D vite-plugin-elm
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
In `vite.config.(js|ts)`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { defineConfig } from 'vite'
|
|
25
|
+
import elmPlugin from 'vite-plugin-elm'
|
|
26
|
+
|
|
27
|
+
export default defineConfig({
|
|
28
|
+
plugins: [elmPlugin()]
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then you can import a `.elm` file and run it like:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Elm } from './Hello.elm'
|
|
36
|
+
|
|
37
|
+
// Mount "Hello" Browser.{element,document} on #root
|
|
38
|
+
Elm.Hello.init({
|
|
39
|
+
node: document.getElementById('root'),
|
|
40
|
+
flags: "Initial Message"
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can explore the [`/example`](/example) directory to experiment with an actual Vite project. Additionally, [this functional website](https://github.com/hmsk/hmsk.me) can serve as a helpful resource to learn how to use it effectively.
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
### `debug` (Default: `process.env.NODE_ENV !== 'production'`)
|
|
49
|
+
|
|
50
|
+
You can control the debug mode of Elm, which toggles the Elm Debugger, by providing a boolean value.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
elmPlugin({ debug: false })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
When set to `false`, it disables debug mode in both development and production. Conversely, setting it to `true` enables debug mode even in production. It's important to note that **when the production build has debug mode enabled, Elm's compiler optimizations do not take place**.
|
|
59
|
+
|
|
60
|
+
### `optimize` (Default: `!debug && process.env.NODE_ENV === 'production'`)
|
|
61
|
+
|
|
62
|
+
You can control build optimization by providing a boolean value, which can be useful for using [`Debug`](https://package.elm-lang.org/packages/elm/core/latest/Debug) functions in your Elm code.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
elmPlugin({ debug: false, optimize: false })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When set to `true`, it optimizes the build and prohibits the usage of Debug Elm functions. If you specify the optimize attribute, you must indicate whether debugging is needed. This is because you might want to have debug traces for the purpose of observing all actions, not necessarily for debugging specific issues.
|
|
69
|
+
|
|
70
|
+
## Static Assets Handling
|
|
71
|
+
|
|
72
|
+
This plugin supports importing assets by using a specific tag `[VITE_PLUGIN_ELM_ASSET:<path to asset>]` to leverage [Vite's asset handling](https://vitejs.dev/guide/assets.html#importing-asset-as-ur). When your Elm code contains a tag, this plugin replaces that string with the imported asset. It's important to note that the string should be a standalone string without any concatenation.
|
|
73
|
+
|
|
74
|
+
```elm
|
|
75
|
+
Html.img [ Html.Attributes.src "[VITE_PLUGIN_ELM_ASSET:/assets/logo.jpg]" ] []
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Helper package
|
|
79
|
+
|
|
80
|
+
We can simplify the tagging process by using the Elm package `elm-vite-plugin-helper`:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
elm install hmsk/elm-vite-plugin-helper
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```elm
|
|
87
|
+
import VitePluginHelper
|
|
88
|
+
|
|
89
|
+
Html.img [ Html.Attributes.src <| VitePluginHelper.asset "/assets/logo.png?inline" ] []
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Combine multiple main files (Experimental)
|
|
93
|
+
|
|
94
|
+
By passing importing paths via the `with` URL-ish parameter(s), the plugin compiles multiple main files in a single compilation process. This results in a single Elm export that contains multiple properties, each corresponding to a given main file. This feature helps reduce the bundle size when compared to importing each file separately because common modules and Elm core code are not repeated.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// `Elm.App` and `Elm.Another`, both can work as like importing individually.
|
|
98
|
+
import { Elm } from './App.elm?with=./Another.elm'
|
|
99
|
+
|
|
100
|
+
Elm.App.init({
|
|
101
|
+
node: document.getElementById('rootForApp'),
|
|
102
|
+
})
|
|
103
|
+
Elm.Another.init({
|
|
104
|
+
node: document.getElementById('rootForAnother'),
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For 3+ main files:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { Elm } from './App.elm?with=./Another.elm&with=./YetAnother.elm'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Acknowledgement
|
|
115
|
+
|
|
116
|
+
- [klazuka/elm-hot](https://github.com/klazuka/elm-hot) for a helpful referrence of the HMR implementation
|
|
117
|
+
- [ChristophP/elm-esm](https://github.com/ChristophP/elm-esm/issues/2) for publishing IIFE -> ESM logic
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
[MIT](/LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const injectAssets: (compiledESM: string) => string;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { parse } from 'acorn';
|
|
2
|
+
import { fullAncestor as walk } from 'acorn-walk';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
const ASSET_TAG = /'\[VITE_PLUGIN_ELM_ASSET:(?<path>.+?)\]'/g;
|
|
5
|
+
const HELPER_PACKAGE_IDENTIFIER = 'VITE_PLUGIN_HELPER_ASSET';
|
|
6
|
+
const importNameFrom = (path) => {
|
|
7
|
+
return '_' + crypto.createHash('sha1').update(path).digest('hex');
|
|
8
|
+
};
|
|
9
|
+
const generateImports = (paths) => {
|
|
10
|
+
return paths.map((path) => `import ${importNameFrom(path)} from '${path}'`).join('\n');
|
|
11
|
+
};
|
|
12
|
+
const isLiteral = (node) => node.type === 'Literal';
|
|
13
|
+
const isDeclarator = (node) => node.type === 'VariableDeclarator';
|
|
14
|
+
const isCallExpression = (node) => node.type === 'CallExpression';
|
|
15
|
+
export const injectAssets = (compiledESM) => {
|
|
16
|
+
const taggedPaths = [];
|
|
17
|
+
const ast = parse(compiledESM, { ecmaVersion: 'latest', sourceType: 'module' });
|
|
18
|
+
let helperFunctionName;
|
|
19
|
+
walk(ast, (node, state) => {
|
|
20
|
+
if (isLiteral(node)) {
|
|
21
|
+
// Find callers of VitePluginHelper.asset
|
|
22
|
+
if (!helperFunctionName && node.raw === `'${HELPER_PACKAGE_IDENTIFIER}'`) {
|
|
23
|
+
const helperFunc = state?.find((nodeOnState) => isDeclarator(nodeOnState) &&
|
|
24
|
+
nodeOnState?.init?.body?.body?.[0]?.argument?.left?.raw === `'${HELPER_PACKAGE_IDENTIFIER}'`);
|
|
25
|
+
if (helperFunc?.id?.name) {
|
|
26
|
+
helperFunctionName = helperFunc.id.name;
|
|
27
|
+
walk(ast, (node) => {
|
|
28
|
+
if (isCallExpression(node) && node?.callee?.name === helperFunctionName) {
|
|
29
|
+
if (node?.arguments?.length === 1 && isLiteral(node.arguments[0])) {
|
|
30
|
+
const matchedPath = node.arguments[0].value;
|
|
31
|
+
taggedPaths.push({
|
|
32
|
+
path: matchedPath,
|
|
33
|
+
start: node.start,
|
|
34
|
+
end: node.end,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
throw 'Arguments for VitePluginHelper should be just a plain String';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, undefined, null);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Find plain asset tags
|
|
46
|
+
const matched = ASSET_TAG.exec(node.raw);
|
|
47
|
+
if (matched !== null) {
|
|
48
|
+
if (matched.groups?.path) {
|
|
49
|
+
taggedPaths.push({
|
|
50
|
+
path: matched.groups.path,
|
|
51
|
+
start: node.start,
|
|
52
|
+
end: node.end,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, undefined, undefined);
|
|
58
|
+
if (taggedPaths.length > 0) {
|
|
59
|
+
const src = compiledESM.split('');
|
|
60
|
+
const importPaths = [];
|
|
61
|
+
taggedPaths.forEach(({ path, start, end }) => {
|
|
62
|
+
for (let i = start; i < end; i++) {
|
|
63
|
+
src[i] = '';
|
|
64
|
+
}
|
|
65
|
+
src[start] = importNameFrom(path);
|
|
66
|
+
if (!importPaths.includes(path)) {
|
|
67
|
+
importPaths.push(path);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return `${generateImports(importPaths)}\n\n${src.join('')}`;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return compiledESM;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=assetsInjector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetsInjector.js","sourceRoot":"","sources":["../src/assetsInjector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface NodeElmCompilerOptions {
|
|
2
|
+
cwd: string;
|
|
3
|
+
docs: string;
|
|
4
|
+
debug: boolean;
|
|
5
|
+
optimize: boolean;
|
|
6
|
+
processOpts: Record<string, string>;
|
|
7
|
+
report: string;
|
|
8
|
+
pathToElm: string;
|
|
9
|
+
verbose: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface CustomCompiler {
|
|
12
|
+
compile: (targets: string[]) => Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare const compile: (targets: string[], options: Partial<NodeElmCompilerOptions> | CustomCompiler) => Promise<string>;
|
package/dist/compiler.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//@ts-expect-error typing isn't provided
|
|
2
|
+
import { toESModule } from 'elm-esm';
|
|
3
|
+
//@ts-expect-error typing isn't provided
|
|
4
|
+
import nodeElmCompiler from 'node-elm-compiler';
|
|
5
|
+
import { findUpSync } from 'find-up';
|
|
6
|
+
import { dirname } from 'path';
|
|
7
|
+
import { injectAssets } from './assetsInjector.js';
|
|
8
|
+
const findClosestElmJson = (pathname) => {
|
|
9
|
+
const elmJson = findUpSync('elm.json', { cwd: dirname(pathname) });
|
|
10
|
+
return elmJson ? dirname(elmJson) : undefined;
|
|
11
|
+
};
|
|
12
|
+
export const compile = async (targets, options) => {
|
|
13
|
+
const compiled = 'compile' in options
|
|
14
|
+
? await runCustomCompiler(targets, options.compile)
|
|
15
|
+
: await nodeElmCompiler.compileToString(targets, {
|
|
16
|
+
output: '.js',
|
|
17
|
+
cwd: findClosestElmJson(targets[0]),
|
|
18
|
+
...options,
|
|
19
|
+
});
|
|
20
|
+
return injectAssets(toESModule(compiled));
|
|
21
|
+
};
|
|
22
|
+
const runCustomCompiler = async (targets, compile) => {
|
|
23
|
+
return compile(targets).catch((e) => {
|
|
24
|
+
throw `Failed to run command: ${e}`;
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=compiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler.js","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,wCAAwC;AACxC,OAAO,eAAe,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE9B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAiBlD,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAE,EAAE;IAC9C,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAClE,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC/C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAC1B,OAAiB,EACjB,OAAyD,EACxC,EAAE;IACnB,MAAM,QAAQ,GACZ,SAAS,IAAI,OAAO;QAClB,CAAC,CAAC,MAAM,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;QACnD,CAAC,CAAC,MAAM,eAAe,CAAC,eAAe,CAAC,OAAO,EAAE;YAC7C,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACnC,GAAG,OAAO;SACX,CAAC,CAAA;IACR,OAAO,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC3C,CAAC,CAAA;AAED,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAAiB,EAAE,OAAkC,EAAE,EAAE;IACxF,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,MAAM,0BAA0B,CAAC,EAAE,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { expect, it, vi } from 'vitest';
|
|
2
|
+
//@ts-expect-error typing isn't provided
|
|
3
|
+
import nodeElmCompiler from 'node-elm-compiler';
|
|
4
|
+
import { compile } from './compiler.js';
|
|
5
|
+
const compiled = `_Platform_export({'Hello':{'init':$author$project$Hello$main($elm$json$Json$Decode$string)({'versions':{'elm':'0.19.1'},'types':{'message':'Hello.Msg','aliases':{},'unions':{'Hello.Msg':{'args':[],'tags':{'Name':['String.String']}},'String.String':{'args':[],'tags':{'String':[]}}}}})}});}(this));`;
|
|
6
|
+
it('calls node-elm-compiler', async () => {
|
|
7
|
+
vi.spyOn(nodeElmCompiler, 'compileToString').mockImplementation(() => compiled);
|
|
8
|
+
expect(await compile(['a', 'b', 'c'], { debug: false, optimize: true, verbose: true })).toMatch(/export const Elm = {'Hello':/);
|
|
9
|
+
expect(nodeElmCompiler.compileToString).toBeCalledWith(['a', 'b', 'c'], {
|
|
10
|
+
output: '.js',
|
|
11
|
+
debug: false,
|
|
12
|
+
optimize: true,
|
|
13
|
+
verbose: true,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
it('executes manual command', async () => {
|
|
17
|
+
expect(await compile(['a', 'b', 'c'], {
|
|
18
|
+
compile: async (targets) => (targets[1] === 'b' ? compiled : ''),
|
|
19
|
+
})).toMatch(/export const Elm = {'Hello':/);
|
|
20
|
+
});
|
|
21
|
+
it('executes manual command which fails', async () => {
|
|
22
|
+
expect(compile(['a', 'b', 'c'], {
|
|
23
|
+
compile: async () => Promise.reject('sad'),
|
|
24
|
+
})).rejects.toMatch(/Failed to run command/);
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=compiler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler.test.js","sourceRoot":"","sources":["../src/compiler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACvC,wCAAwC;AACxC,OAAO,eAAe,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,QAAQ,GAAG,2SAA2S,CAAA;AAE5T,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;IACvC,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAA;IAE/E,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAC7F,8BAA8B,CAC/B,CAAA;IAED,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE;QACtE,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,IAAI;KACd,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;IACvC,MAAM,CACJ,MAAM,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE;QAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC,CACH,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAA;AAC3C,CAAC,CAAC,CAAA;AAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;IACnD,MAAM,CACJ,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE;QACvB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;KAC3C,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAA;AAC5C,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const injectHMR: (compiledESM: string, dependencies: string[]) => string;
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
const injectElmHot = (compiledESM, dependencies) => `
|
|
2
|
+
${compiledESM}
|
|
3
|
+
|
|
4
|
+
/* This HMR code is heavily basing on elm-hot by Keith Lazuka which is published under the MIT License
|
|
5
|
+
* https://github.com/klazuka/elm-hot
|
|
6
|
+
* https://github.com/klazuka/elm-hot/blob/master/LICENSE.txt
|
|
7
|
+
*/
|
|
8
|
+
if (import.meta.hot) {
|
|
9
|
+
let elmVersion
|
|
10
|
+
if (typeof elm$core$Maybe$Just !== 'undefined') {
|
|
11
|
+
elmVersion = '0.19.0'
|
|
12
|
+
} else if (typeof $elm$core$Maybe$Just !== 'undefined') {
|
|
13
|
+
elmVersion = '0.19.1'
|
|
14
|
+
} else {
|
|
15
|
+
throw new Error("Could not determine Elm version")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const elmSymbol = (symbol) => {
|
|
19
|
+
try {
|
|
20
|
+
switch (elmVersion) {
|
|
21
|
+
case '0.19.0':
|
|
22
|
+
return eval(symbol);
|
|
23
|
+
case '0.19.1':
|
|
24
|
+
return eval('$' + symbol);
|
|
25
|
+
default:
|
|
26
|
+
throw new Error('Cannot resolve ' + symbol + '. Elm version unknown!')
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {
|
|
29
|
+
if (e instanceof ReferenceError) {
|
|
30
|
+
return undefined;
|
|
31
|
+
} else {
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const instances = import.meta.hot.data ? import.meta.hot.data.instances || {} : {}
|
|
38
|
+
let uid = import.meta.hot.data ? import.meta.hot.data.uid || 0 : 0
|
|
39
|
+
|
|
40
|
+
if (Object.keys(instances).length === 0) console.log("[vite-plugin-elm] HMR enabled")
|
|
41
|
+
|
|
42
|
+
const cancellers = []
|
|
43
|
+
let initializingInstance = null
|
|
44
|
+
let swappingInstance = null
|
|
45
|
+
|
|
46
|
+
import.meta.hot.accept()
|
|
47
|
+
const dependencies = [${dependencies.map(d => `"${d}"`).join('", "')}]
|
|
48
|
+
if (dependencies.length > 0) {
|
|
49
|
+
import.meta.hot.accept(dependencies, () => {
|
|
50
|
+
console.log("[vite-plugin-elm] Dependency is updated")
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
import.meta.hot.on('hot-update-dependents', (data) => {
|
|
55
|
+
console.log("[vite-plugin-elm] Request to hot update dependents: " + data.join(", "))
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
import.meta.hot.dispose((data) => {
|
|
59
|
+
data.instances = instances
|
|
60
|
+
data.uid = uid
|
|
61
|
+
|
|
62
|
+
_Scheduler_binding = () => _Scheduler_fail(new Error("[vite-plugin-elm] Inactive Elm instance."))
|
|
63
|
+
|
|
64
|
+
if (cancellers.length) {
|
|
65
|
+
console.log("[vite-plugin-elm] Killing " + cancellers.length + " running processes...")
|
|
66
|
+
try {
|
|
67
|
+
cancellers.forEach((cancel) => { cancel() })
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.warn("[vite-plugin-elm] Kill process error: ", e.message)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const getId = () => ++uid
|
|
75
|
+
|
|
76
|
+
const findPublicModules = (parent, path) => {
|
|
77
|
+
let modules = []
|
|
78
|
+
Object.keys(parent).forEach((key) => {
|
|
79
|
+
const child = parent[key]
|
|
80
|
+
const currentPath = path ? path + '.' + key : key
|
|
81
|
+
if ('init' in child) {
|
|
82
|
+
modules.push({ path: currentPath, module: child })
|
|
83
|
+
} else {
|
|
84
|
+
modules = [ ...modules, ...findPublicModules(child, currentPath) ]
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
return modules
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const registerInstance = (domNode, flags, path, portSubscribes, portSends) => {
|
|
91
|
+
const id = getId()
|
|
92
|
+
const instance = {
|
|
93
|
+
id, path, domNode, flags, portSubscribes, portSends,
|
|
94
|
+
lastState: null,
|
|
95
|
+
initialState: null
|
|
96
|
+
}
|
|
97
|
+
return instances[id] = instance
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isFullscreenApp = () => typeof elmSymbol("elm$browser$Browser$application") !== 'undefined' || typeof elmSymbol("elm$browser$Browser$document") !== 'undefined'
|
|
101
|
+
|
|
102
|
+
const wrapDomNode = (node) => {
|
|
103
|
+
const dummyNode = document.createElement("div")
|
|
104
|
+
dummyNode.setAttribute("data-elm-hot", "true")
|
|
105
|
+
dummyNode.style.height = "inherit"
|
|
106
|
+
const parentNode = node.parentNode
|
|
107
|
+
parentNode.replaceChild(dummyNode, node)
|
|
108
|
+
dummyNode.appendChild(node)
|
|
109
|
+
return dummyNode
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const wrapPublicModule = (path, module) => {
|
|
113
|
+
const originalInit = module.init
|
|
114
|
+
if (originalInit) {
|
|
115
|
+
module.init = (args) => {
|
|
116
|
+
let elm
|
|
117
|
+
const portSubscribes = {}
|
|
118
|
+
const portSends = {}
|
|
119
|
+
let domNode = null
|
|
120
|
+
let flags = undefined
|
|
121
|
+
if (typeof args !== 'undefined') {
|
|
122
|
+
domNode = args['node'] && !isFullscreenApp() ? wrapDomNode(args['node']) : document.body
|
|
123
|
+
flags = args['flags']
|
|
124
|
+
} else {
|
|
125
|
+
domNode = document.body
|
|
126
|
+
}
|
|
127
|
+
initializingInstance = registerInstance(domNode, flags, path, portSubscribes, portSends)
|
|
128
|
+
elm = originalInit(args)
|
|
129
|
+
wrapPorts(elm, portSubscribes, portSends)
|
|
130
|
+
initializingInstance = null
|
|
131
|
+
return elm
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
console.error("Could not find a public module to wrap at path " + path)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const swap = (Elm, instance) => {
|
|
139
|
+
console.log("[vite-plugin-elm] Hot-swapping module:", instance.path)
|
|
140
|
+
swappingInstance = instance
|
|
141
|
+
|
|
142
|
+
const containerNode = instance.domNode
|
|
143
|
+
while (containerNode.lastChild) {
|
|
144
|
+
containerNode.removeChild(containerNode.lastChild)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const m = getAt(instance.path.split('.'), Elm)
|
|
148
|
+
if (m) {
|
|
149
|
+
const args = { flags: instance.flags }
|
|
150
|
+
if (containerNode === document.body) {
|
|
151
|
+
// fullscreen
|
|
152
|
+
} else {
|
|
153
|
+
const nodeForEmbed = document.createElement("div")
|
|
154
|
+
containerNode.appendChild(nodeForEmbed)
|
|
155
|
+
args.node = nodeForEmbed
|
|
156
|
+
}
|
|
157
|
+
const elm = m.init(args)
|
|
158
|
+
|
|
159
|
+
Object.keys(instance.portSubscribes).forEach((portName) => {
|
|
160
|
+
if (portName in elm.ports && 'subscribe' in elm.ports[portName]) {
|
|
161
|
+
const handlers = instance.portSubscribes[portName]
|
|
162
|
+
if (!handlers.length) return
|
|
163
|
+
console.log("[vite-plugin-elm] Reconnect", handlers.length + " handlers(s) to port '" + portName + "' (" + instance.path + ").")
|
|
164
|
+
handlers.forEach(elm.ports[portName].subscribe)
|
|
165
|
+
} else {
|
|
166
|
+
delete instance.portSubscribes[portName]
|
|
167
|
+
console.log("[vite-plugin-elm] Port was removed:", portName)
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
Object.keys(instance.portSends).forEach((portName) => {
|
|
172
|
+
if (portName in elm.ports && 'send' in elm.ports[portName]) {
|
|
173
|
+
console.log("[vite-plugin-elm] Replace old port send with the new send")
|
|
174
|
+
instance.portSends[portName] = elm.ports[portName].send
|
|
175
|
+
} else {
|
|
176
|
+
delete instance.portSends[portName]
|
|
177
|
+
console.log("[vite-plugin-elm] Port was removed:", portName)
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
} else {
|
|
181
|
+
console.log("[vite-plugin-elm] Module was removed:", instance.path)
|
|
182
|
+
}
|
|
183
|
+
swappingInstance = null
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const wrapPorts = (elm, portSubscribes, portSends) => {
|
|
187
|
+
const portNames = Object.keys(elm.ports || {})
|
|
188
|
+
if (portNames.length) {
|
|
189
|
+
portNames
|
|
190
|
+
.filter(name => "subscribe" in elm.ports[name])
|
|
191
|
+
.forEach((portName) => {
|
|
192
|
+
const port = elm.ports[portName]
|
|
193
|
+
const subscribe = port.subscribe
|
|
194
|
+
const unsubscribe = port.unsubscribe
|
|
195
|
+
elm.ports[portName] = Object.assign(port, {
|
|
196
|
+
subscribe: (handler) => {
|
|
197
|
+
console.log("[vite-plugin-elm] ports.", portName + ".subscribe called")
|
|
198
|
+
if (!portSubscribes[portName]) {
|
|
199
|
+
portSubscribes[portName] = [handler]
|
|
200
|
+
} else {
|
|
201
|
+
portSubscribes[portName].push(handler)
|
|
202
|
+
}
|
|
203
|
+
return subscribe.call(port, handler)
|
|
204
|
+
},
|
|
205
|
+
unsubscribe: (handler) => {
|
|
206
|
+
console.log("[vite-plugin-elm] ports.", portName + ".unsubscribe called.")
|
|
207
|
+
const list = portSubscribes[portName]
|
|
208
|
+
if (list && list.indexOf(handler) !== -1) {
|
|
209
|
+
list.splice(list.lastIndexOf(handler), 1)
|
|
210
|
+
} else {
|
|
211
|
+
console.warn("[vite-plugin-elm] ports.", portName + ".unsubscribe: handler not subscribed")
|
|
212
|
+
}
|
|
213
|
+
return unsubscribe.call(port, handler)
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
portNames
|
|
219
|
+
.filter(name => "send" in elm.ports[name])
|
|
220
|
+
.forEach((portName) => {
|
|
221
|
+
const port = elm.ports[portName]
|
|
222
|
+
portSends[portName] = port.send
|
|
223
|
+
elm.ports[portName] = Object.assign(port, {
|
|
224
|
+
send: (val) => portSends[portName].call(port, val)
|
|
225
|
+
})
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return portSubscribes
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const isDebuggerModel = (model) => model && (model.hasOwnProperty("expando") || model.hasOwnProperty("expandoModel")) && model.hasOwnProperty("state")
|
|
233
|
+
|
|
234
|
+
const findNavKey = (rootModel) => {
|
|
235
|
+
const queue = []
|
|
236
|
+
if (isDebuggerModel(rootModel)) {
|
|
237
|
+
queue.push({ value: rootModel['state'], keypath: ['state'] })
|
|
238
|
+
} else {
|
|
239
|
+
queue.push({ value: rootModel, keypath: [] })
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
while (queue.length !== 0) {
|
|
243
|
+
const item = queue.shift()
|
|
244
|
+
if (typeof item.value === "undefined" || item.value === null) continue
|
|
245
|
+
if (item.value.hasOwnProperty("elm-hot-nav-key")) return item
|
|
246
|
+
if (typeof item.value !== "object") continue
|
|
247
|
+
|
|
248
|
+
for (const propName in item.value) {
|
|
249
|
+
if (!item.value.hasOwnProperty(propName)) continue
|
|
250
|
+
const newKeypath = item.keypath.slice()
|
|
251
|
+
newKeypath.push(propName)
|
|
252
|
+
queue.push({ value: item.value[propName], keypath: newKeypath })
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const getAt = (keyPath, obj) => keyPath.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, obj)
|
|
259
|
+
const removeNavKeyListeners = (navKey) => {
|
|
260
|
+
window.removeEventListener("popstate", navKey.value)
|
|
261
|
+
window.navigator.userAgent.indexOf("Trident") < 0 || window.removeEventListener("hashchange", navKey.value)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const initialize = _Platform_initialize
|
|
265
|
+
_Platform_initialize = (flagDecoder, args, init, update, subscriptions, stepperBuilder) => {
|
|
266
|
+
const instance = initializingInstance || swappingInstance
|
|
267
|
+
let tryFirstRender = !!swappingInstance
|
|
268
|
+
|
|
269
|
+
const hookedInit = (args) => {
|
|
270
|
+
const initialStateTuple = init(args)
|
|
271
|
+
if (swappingInstance) {
|
|
272
|
+
let oldModel = swappingInstance.lastState
|
|
273
|
+
const newModel = initialStateTuple.a
|
|
274
|
+
|
|
275
|
+
if (JSON.stringify(newModel.state?.a ? newModel.state.a : newModel) !== swappingInstance.initialState) {
|
|
276
|
+
console.log("[vite-plugin-elm] Initial state seems to be updated. Refreshes page")
|
|
277
|
+
import.meta.hot.invalidate()
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (typeof elmSymbol("elm$browser$Browser$application") !== "undefined" && typeof elmSymbol("elm$browser$Browser$Navigation") !== "undefined") {
|
|
281
|
+
const oldKeyLoc = findNavKey(oldModel)
|
|
282
|
+
const newKeyLoc = findNavKey(newModel)
|
|
283
|
+
let error = null
|
|
284
|
+
if (newKeyLoc === null) {
|
|
285
|
+
error = "could not find Browser.Navigation.Key in the new app model"
|
|
286
|
+
} else if (oldKeyLoc === null) {
|
|
287
|
+
error = "could not find Browser.Navigation.Key in the old app model"
|
|
288
|
+
} else if (newKeyLoc.keypath.toString() !== oldKeyLoc.keypath.toString()) {
|
|
289
|
+
error = "the location of the Browser.Navigation.Key in the model has changed.";
|
|
290
|
+
} else {
|
|
291
|
+
removeNavKeyListeners(oldKeyLoc.value)
|
|
292
|
+
const parentKeyPath = oldKeyLoc.keypath.slice(0, -1)
|
|
293
|
+
const lastSegment = oldKeyLoc.keypath.slice(-1)[0]
|
|
294
|
+
const oldParent = getAt(parentKeyPath, oldModel)
|
|
295
|
+
oldParent[lastSegment] = newKeyLoc.value
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (error !== null) {
|
|
299
|
+
console.error("[vite-plugin-elm] Hot-swapping", instance.path + " not possible: " + error)
|
|
300
|
+
oldModel = newModel
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
initialStateTuple.a = oldModel
|
|
304
|
+
initialStateTuple.b = elmSymbol("elm$core$Platform$Cmd$none")
|
|
305
|
+
} else {
|
|
306
|
+
initializingInstance.lastState = initialStateTuple.a
|
|
307
|
+
initializingInstance.initialState = JSON.stringify(initialStateTuple.a.state?.a ? initialStateTuple.a.state.a : initialStateTuple.a)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return initialStateTuple
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const hookedStepperBuilder = (sendToApp, model) => {
|
|
314
|
+
let result
|
|
315
|
+
if (tryFirstRender) {
|
|
316
|
+
tryFirstRender = false
|
|
317
|
+
try {
|
|
318
|
+
result = stepperBuilder(sendToApp, model)
|
|
319
|
+
} catch (e) {
|
|
320
|
+
throw new Error("[vite-plugin-elm] Hot-swapping " + instance.path + " is not possible, please reload page. Error: " + e.message)
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
result = stepperBuilder(sendToApp, model)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return (nextModel, isSync) => {
|
|
327
|
+
if (instance) instance.lastState = nextModel
|
|
328
|
+
return result(nextModel, isSync)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return initialize(flagDecoder, args, hookedInit, update, subscriptions, hookedStepperBuilder)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const originalBinding = _Scheduler_binding
|
|
336
|
+
_Scheduler_binding = (originalCallback) => originalBinding(function () {
|
|
337
|
+
const cancel = originalCallback.apply(this, arguments)
|
|
338
|
+
if (cancel) {
|
|
339
|
+
cancellers.push(cancel)
|
|
340
|
+
return () => {
|
|
341
|
+
cancellers.splice(cancellers.indexOf(cancel), 1)
|
|
342
|
+
return cancel()
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
const swapInstances = (Elm) => {
|
|
348
|
+
const removedInstances = []
|
|
349
|
+
Object.entries(instances).forEach(([id, instance]) => {
|
|
350
|
+
if (instance.domNode.parentNode) {
|
|
351
|
+
swap(Elm, instance)
|
|
352
|
+
} else {
|
|
353
|
+
removedInstances.push(id)
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
removedInstances.forEach((id) => {
|
|
358
|
+
delete instance[id]
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
findPublicModules(Elm).forEach((m) => {
|
|
362
|
+
wrapPublicModule(m.path, m.module)
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
swapInstances(Elm)
|
|
367
|
+
}
|
|
368
|
+
`;
|
|
369
|
+
// https://github.com/klazuka/elm-hot/blob/master/src/inject.js#L16
|
|
370
|
+
const hotFixForElmHotNavKey = (esm) => {
|
|
371
|
+
const hotFixForMissingKey = 'function() { key.a(onUrlChange(_Browser_getUrl())); };';
|
|
372
|
+
return esm.includes('elm$browser$Browser$application')
|
|
373
|
+
? esm.replace(hotFixForMissingKey, `${hotFixForMissingKey}\n\tkey['elm-hot-nav-key'] = true;\n`)
|
|
374
|
+
: esm;
|
|
375
|
+
};
|
|
376
|
+
export const injectHMR = (compiledESM, dependencies) => injectElmHot(hotFixForElmHotNavKey(compiledESM), dependencies);
|
|
377
|
+
//# sourceMappingURL=hmrInjector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmrInjector.js","sourceRoot":"","sources":["../src/hmrInjector.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,YAAsB,EAAU,EAAE,CAAC;EAC5E,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA6Ca,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiUrE,CAAA;AAED,mEAAmE;AACnE,MAAM,qBAAqB,GAAG,CAAC,GAAW,EAAU,EAAE;IACpD,MAAM,mBAAmB,GAAG,wDAAwD,CAAA;IACpF,OAAO,GAAG,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QACpD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,mBAAmB,sCAAsC,CAAC;QAChG,CAAC,CAAC,GAAG,CAAA;AACT,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,WAAmB,EAAE,YAAsB,EAAU,EAAE,CAC/E,YAAY,CAAC,qBAAqB,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC,CAAA"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
//@ts-expect-error typing isn't provided
|
|
2
|
+
import nodeElmcompiler from 'node-elm-compiler';
|
|
3
|
+
import { normalize, relative } from 'path';
|
|
4
|
+
import { injectHMR } from './hmrInjector.js';
|
|
5
|
+
import { acquireLock } from './mutex.js';
|
|
6
|
+
import { parseOptions } from './pluginOptions.js';
|
|
7
|
+
import { compile } from './compiler.js';
|
|
8
|
+
const trimDebugMessage = (code) => code.replace(/(console\.warn\('Compiled in DEBUG mode)/, '// $1');
|
|
9
|
+
const viteProjectPath = (dependency) => `/${relative(process.cwd(), dependency)}`;
|
|
10
|
+
const parseImportId = (id) => {
|
|
11
|
+
const parsedId = new URL(id, 'file://');
|
|
12
|
+
const pathname = parsedId.pathname;
|
|
13
|
+
const valid = pathname.endsWith('.elm') && !parsedId.searchParams.has('raw');
|
|
14
|
+
const withParams = parsedId.searchParams.getAll('with');
|
|
15
|
+
return {
|
|
16
|
+
valid,
|
|
17
|
+
pathname,
|
|
18
|
+
withParams,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export const plugin = (userOptions = {}) => {
|
|
22
|
+
const options = parseOptions(userOptions);
|
|
23
|
+
const compilableFiles = new Map();
|
|
24
|
+
return {
|
|
25
|
+
name: 'vite-plugin-elm',
|
|
26
|
+
enforce: 'pre',
|
|
27
|
+
handleHotUpdate({ file, server, modules }) {
|
|
28
|
+
const { valid } = parseImportId(file);
|
|
29
|
+
if (!valid)
|
|
30
|
+
return;
|
|
31
|
+
const modulesToCompile = [];
|
|
32
|
+
compilableFiles.forEach((dependencies, compilableFile) => {
|
|
33
|
+
if (dependencies.has(normalize(file))) {
|
|
34
|
+
const module = server.moduleGraph.getModuleById(compilableFile);
|
|
35
|
+
if (module)
|
|
36
|
+
modulesToCompile.push(module);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (modulesToCompile.length > 0) {
|
|
40
|
+
server.ws.send({
|
|
41
|
+
type: 'custom',
|
|
42
|
+
event: 'hot-update-dependents',
|
|
43
|
+
data: modulesToCompile.map(({ url }) => url),
|
|
44
|
+
});
|
|
45
|
+
return modulesToCompile;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return modules;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
async load(id) {
|
|
52
|
+
const { valid, pathname, withParams } = parseImportId(id);
|
|
53
|
+
if (!valid)
|
|
54
|
+
return;
|
|
55
|
+
const accompanies = await (() => {
|
|
56
|
+
if (withParams.length > 0) {
|
|
57
|
+
const importTree = this.getModuleIds();
|
|
58
|
+
let importer = '';
|
|
59
|
+
for (const moduleId of importTree) {
|
|
60
|
+
if (moduleId === id)
|
|
61
|
+
break;
|
|
62
|
+
importer = moduleId;
|
|
63
|
+
}
|
|
64
|
+
const resolveAccompany = async (accompany) => (await this.resolve(accompany, importer))?.id ?? '';
|
|
65
|
+
return Promise.all(withParams.map(resolveAccompany));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return Promise.resolve([]);
|
|
69
|
+
}
|
|
70
|
+
})();
|
|
71
|
+
const targets = [pathname, ...accompanies].filter((target) => target !== '');
|
|
72
|
+
compilableFiles.delete(id);
|
|
73
|
+
const dependencies = (await Promise.all(targets.map((target) => nodeElmcompiler.findAllDependencies(target)))).flat();
|
|
74
|
+
compilableFiles.set(id, new Set([...accompanies, ...dependencies]));
|
|
75
|
+
const releaseLock = await acquireLock();
|
|
76
|
+
try {
|
|
77
|
+
const compiled = await compile(targets, options.compilerOptions);
|
|
78
|
+
// Apparently `addWatchFile` may not exist: https://github.com/hmsk/vite-plugin-elm/pull/36
|
|
79
|
+
if (this.addWatchFile) {
|
|
80
|
+
dependencies.forEach(this.addWatchFile.bind(this));
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
code: options.isBuild ? compiled : trimDebugMessage(injectHMR(compiled, dependencies.map(viteProjectPath))),
|
|
84
|
+
map: null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
if (e instanceof Error && e.message.includes('-- NO MAIN')) {
|
|
89
|
+
const message = `${viteProjectPath(pathname)}: NO MAIN .elm file is requested to transform by vite. Probably, this file is just a depending module`;
|
|
90
|
+
throw message;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
releaseLock();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
export default plugin;
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/mutex.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const acquireLock: () => Promise<() => void>;
|
package/dist/mutex.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This approach comes from snowpack-plugin-elm by Marc Walter
|
|
3
|
+
* https://github.com/marc136/snowpack-plugin-elm
|
|
4
|
+
*
|
|
5
|
+
* To avoid gets an error: "It looks like some of the information cached in elm-stuff/ has been corrupted." from Elm compiler
|
|
6
|
+
* Elm compiler uses elm-stuff dir for cache which is expected not to be touched by other thread's compilation
|
|
7
|
+
*/
|
|
8
|
+
const queue = [];
|
|
9
|
+
let locked = false;
|
|
10
|
+
export const acquireLock = async () => {
|
|
11
|
+
await new Promise((resolve) => {
|
|
12
|
+
if (!locked) {
|
|
13
|
+
resolve();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
queue.push(resolve);
|
|
17
|
+
});
|
|
18
|
+
locked = true;
|
|
19
|
+
return () => {
|
|
20
|
+
queue.shift()?.();
|
|
21
|
+
if (queue.length === 0) {
|
|
22
|
+
locked = false;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=mutex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutex.js","sourceRoot":"","sources":["../src/mutex.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,KAAK,GAAmB,EAAE,CAAA;AAChC,IAAI,MAAM,GAAG,KAAK,CAAA;AAElB,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;IACpC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,CAAA;YACT,OAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACrB,CAAC,CAAC,CAAA;IAEF,MAAM,GAAG,IAAI,CAAA;IAEb,OAAO,GAAG,EAAE;QACV,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,CAAA;QACjB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,KAAK,CAAA;QAChB,CAAC;IACH,CAAC,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CustomCompiler, NodeElmCompilerOptions } from './compiler.js';
|
|
2
|
+
interface InputOptions {
|
|
3
|
+
debug?: boolean;
|
|
4
|
+
optimize?: boolean;
|
|
5
|
+
nodeElmCompilerOptions?: Partial<NodeElmCompilerOptions>;
|
|
6
|
+
compiler?: CustomCompiler;
|
|
7
|
+
}
|
|
8
|
+
type DeterminedKeys = 'debug' | 'optimize' | 'verbose';
|
|
9
|
+
interface ParsedOptions {
|
|
10
|
+
isBuild: boolean;
|
|
11
|
+
compilerOptions: (Pick<NodeElmCompilerOptions, DeterminedKeys> & Partial<Omit<NodeElmCompilerOptions, DeterminedKeys>>) | CustomCompiler;
|
|
12
|
+
}
|
|
13
|
+
export declare const parseOptions: (inputOptions: InputOptions) => ParsedOptions;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const parseOptions = (inputOptions) => {
|
|
2
|
+
const isBuild = process.env.NODE_ENV === 'production';
|
|
3
|
+
return {
|
|
4
|
+
isBuild,
|
|
5
|
+
compilerOptions: inputOptions.compiler ?? {
|
|
6
|
+
debug: inputOptions.debug ?? !isBuild,
|
|
7
|
+
optimize: typeof inputOptions.optimize === 'boolean' ? inputOptions.optimize : !inputOptions.debug && isBuild,
|
|
8
|
+
verbose: isBuild,
|
|
9
|
+
...(inputOptions.nodeElmCompilerOptions ?? {}),
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=pluginOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginOptions.js","sourceRoot":"","sources":["../src/pluginOptions.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,YAA0B,EAAiB,EAAE;IACxE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;IAErD,OAAO;QACL,OAAO;QACP,eAAe,EAAE,YAAY,CAAC,QAAQ,IAAI;YACxC,KAAK,EAAE,YAAY,CAAC,KAAK,IAAI,CAAC,OAAO;YACrC,QAAQ,EAAE,OAAO,YAAY,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,IAAI,OAAO;YAC7G,OAAO,EAAE,OAAO;YAChB,GAAG,CAAC,YAAY,CAAC,sBAAsB,IAAI,EAAE,CAAC;SAC/C;KACF,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { parseOptions } from './pluginOptions.js';
|
|
3
|
+
describe('in dev build', () => {
|
|
4
|
+
it('returns default in dev', () => {
|
|
5
|
+
expect(parseOptions({})).toEqual({
|
|
6
|
+
isBuild: false,
|
|
7
|
+
compilerOptions: {
|
|
8
|
+
debug: true,
|
|
9
|
+
optimize: false,
|
|
10
|
+
verbose: false,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
it('overwrites debug and optimize as it given', () => {
|
|
15
|
+
expect(parseOptions({ debug: false, optimize: true })).toEqual({
|
|
16
|
+
isBuild: false,
|
|
17
|
+
compilerOptions: {
|
|
18
|
+
debug: false,
|
|
19
|
+
optimize: true,
|
|
20
|
+
verbose: false,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it('passes thru options for node-elm-compiler', () => {
|
|
25
|
+
expect(parseOptions({
|
|
26
|
+
nodeElmCompilerOptions: { pathToElm: 'wherever' },
|
|
27
|
+
})).toEqual({
|
|
28
|
+
isBuild: false,
|
|
29
|
+
compilerOptions: {
|
|
30
|
+
debug: true,
|
|
31
|
+
optimize: false,
|
|
32
|
+
verbose: false,
|
|
33
|
+
pathToElm: 'wherever',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it('accepts manual command which omits options for node-elm-compiler', () => {
|
|
38
|
+
expect(parseOptions({
|
|
39
|
+
nodeElmCompilerOptions: { pathToElm: 'wherever' },
|
|
40
|
+
compiler: { compile: async () => 'compiled' },
|
|
41
|
+
})).toEqual({
|
|
42
|
+
isBuild: false,
|
|
43
|
+
compilerOptions: {
|
|
44
|
+
compile: expect.any(Function),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('in production build', () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
vi.stubEnv('NODE_ENV', 'production');
|
|
52
|
+
});
|
|
53
|
+
it('returns default for prod build', () => {
|
|
54
|
+
expect(parseOptions({})).toEqual({
|
|
55
|
+
isBuild: true,
|
|
56
|
+
compilerOptions: {
|
|
57
|
+
debug: false,
|
|
58
|
+
optimize: true,
|
|
59
|
+
verbose: true,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('overwrites debug and optimize per just only debug', () => {
|
|
64
|
+
expect(parseOptions({ debug: true })).toEqual({
|
|
65
|
+
isBuild: true,
|
|
66
|
+
compilerOptions: {
|
|
67
|
+
debug: true,
|
|
68
|
+
optimize: false,
|
|
69
|
+
verbose: true,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it('overwrites debug and optimize', () => {
|
|
74
|
+
expect(parseOptions({ debug: true, optimize: false })).toEqual({
|
|
75
|
+
isBuild: true,
|
|
76
|
+
compilerOptions: {
|
|
77
|
+
debug: true,
|
|
78
|
+
optimize: false,
|
|
79
|
+
verbose: true,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=pluginOptions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginOptions.test.js","sourceRoot":"","sources":["../src/pluginOptions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAIjD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAS;YACvC,OAAO,EAAE,KAAK;YACd,eAAe,EAAE;gBACf,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAS;YACrE,OAAO,EAAE,KAAK;YACd,eAAe,EAAE;gBACf,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CACJ,YAAY,CAAC;YACX,sBAAsB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;SAClD,CAAC,CACH,CAAC,OAAO,CAAS;YAChB,OAAO,EAAE,KAAK;YACd,eAAe,EAAE;gBACf,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,UAAU;aACtB;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CACJ,YAAY,CAAC;YACX,sBAAsB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;YACjD,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,EAAE;SAC9C,CAAC,CACH,CAAC,OAAO,CAAS;YAChB,OAAO,EAAE,KAAK;YACd,eAAe,EAAE;gBACf,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;aAC9B;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAS;YACvC,OAAO,EAAE,IAAI;YACb,eAAe,EAAE;gBACf,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,IAAI;aACd;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAS;YACpD,OAAO,EAAE,IAAI;YACb,eAAe,EAAE;gBACf,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,IAAI;aACd;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAS;YACrE,OAAO,EAAE,IAAI;YACb,eAAe,EAAE;gBACf,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,IAAI;aACd;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@installgen2/vite-plugin-elm",
|
|
3
|
+
"version": "3.1.0-2",
|
|
4
|
+
"description": "Compile Elm with vite",
|
|
5
|
+
"exports": "./dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "tsc -w -p .",
|
|
13
|
+
"build": "rm -rf dist && tsc -p .",
|
|
14
|
+
"lint": "eslint . --max-warnings 0",
|
|
15
|
+
"prettier": "prettier --check .",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"build:example": "cd ./example && npm i && npm run build",
|
|
18
|
+
"build:example:eol2": "cd ./example && npm run build:eol2",
|
|
19
|
+
"test": "vitest",
|
|
20
|
+
"test:ci": "vitest run",
|
|
21
|
+
"test-server:dev": "cd ./example && npm run dev -- --port 8936",
|
|
22
|
+
"test-server:preview": "cd ./example && npm run preview -- --port 8938",
|
|
23
|
+
"cypress:prepare": "run-p test-server:*",
|
|
24
|
+
"cypress:open": "cypress open",
|
|
25
|
+
"cypress:run": "cypress run"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+ssh://git@github.com/hmsk/vite-plugin-elm.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"elm",
|
|
33
|
+
"vite"
|
|
34
|
+
],
|
|
35
|
+
"author": "Kengo Hamasaki <k.hamasaki@gmail.com>",
|
|
36
|
+
"contributors": [
|
|
37
|
+
"James Birtles <jamesb@airca.st>",
|
|
38
|
+
"Marc Walter <walter.marc@outlook.com>",
|
|
39
|
+
"Markus <mapmarkus@gmail.com>",
|
|
40
|
+
"FranzSkuffka <jan@funklang.com>",
|
|
41
|
+
"andrewgryan <andrew.ryan@metoffice.gov.uk>",
|
|
42
|
+
"Steven Vandevelde <icid.asset@gmail.com>",
|
|
43
|
+
"Nathan Bleigh <nathan.bleigh@gmail.com>",
|
|
44
|
+
"Nicolas Bétheuil <wadouk@gmail.com>",
|
|
45
|
+
"Shane Kenney <me@shanek.org>",
|
|
46
|
+
"Lindsay Wardell <lindsay.wardell@noredink.com>",
|
|
47
|
+
"Andreas Molitor <andreas.molitor@andrena.de>",
|
|
48
|
+
"Dave Keen <dev@ruffness.com>",
|
|
49
|
+
"notgne2 <gen2@gen2.space>",
|
|
50
|
+
"Jonas Coch <jonas.coch@bellroy.com>",
|
|
51
|
+
"Matt Polzin <mpolzin@workwithopal.com>",
|
|
52
|
+
"Ryan Schlesinger <ryan@ryanschlesinger.com>",
|
|
53
|
+
"Zach Krzyzanowski <zkrzyz@gmail.com>"
|
|
54
|
+
],
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/hmsk/vite-plugin-elm/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/hmsk/vite-plugin-elm",
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"acorn": "^8.19.0",
|
|
62
|
+
"acorn-walk": "^8.3.5",
|
|
63
|
+
"elm-esm": "1.1.4",
|
|
64
|
+
"find-up": "^8.0.0",
|
|
65
|
+
"node-elm-compiler": "5.0.6"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/node": "26.6.6",
|
|
69
|
+
"cypress": "16.2.1",
|
|
70
|
+
"eslint": "10.14.0",
|
|
71
|
+
"eslint-config-prettier": "10.1.8",
|
|
72
|
+
"npm-run-all": "4.1.5",
|
|
73
|
+
"prettier": "3.9.10",
|
|
74
|
+
"typescript": "6.0.3",
|
|
75
|
+
"typescript-eslint": "^8.72.1",
|
|
76
|
+
"vite": "8.3.6",
|
|
77
|
+
"vitest": "5.1.0"
|
|
78
|
+
},
|
|
79
|
+
"peerDependencies": {
|
|
80
|
+
"vite": ">= 5.0.0"
|
|
81
|
+
}
|
|
82
|
+
}
|