Skip to content

Commit 9c1ad15

Browse files
authoredDec 6, 2023
feat: export one bundle with and one without external dependencies in vanilla-jsoneditor (#353)
BREAKING CHANGE: When using `vanilla-jsoneditor` directly in the browser, you now have to `import { JSONEditor } from 'vanilla-jsoneditor/standalone.js'` instead of `import { JSONEditor } from 'vanilla-jsoneditor'`. For projects with a build setup (React, Vue, Angular) it should be a drop-in replacement.
1 parent ec4b788 commit 9c1ad15

14 files changed

+94
-52
lines changed
 

‎README-VANILLA.md

+24-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,25 @@ Install using npm:
3030
npm install vanilla-jsoneditor
3131
```
3232

33-
Remark: for usage in a Svelte project, install `svelte-jsoneditor` instead.
33+
Remark: for usage in a Svelte project, install and use `svelte-jsoneditor` instead of `vanilla-jsoneditor`.
34+
35+
## Use
36+
37+
If you have a setup for your project with a bundler (like Vite, Rollup, or Webpack), it is best to use the default ES import:
38+
39+
```ts
40+
// for use in a React, Vue, or Angular project
41+
import { JSONEditor } from 'vanilla-jsoneditor'
42+
```
43+
44+
If you want to use the library straight in the browser, use the provided standalone ES bundle:
45+
46+
```ts
47+
// for use directly in the browser
48+
import { JSONEditor } from 'vanilla-jsoneditor/standalone.js'
49+
```
50+
51+
The standalone bundle contains all dependencies of `vanilla-jsoneditor`, for example `lodash-es` and `Ajv`. If you use some of these dependencies in your project too, it means that they will be bundled twice in your web application, leading to a needlessly large application size. In general, it is preferable to use the default `import { JSONEditor } from 'vanilla-jsoneditor'` so dependencies can be reused.
3452

3553
## Use (Browser example loading the ES module):
3654

@@ -44,7 +62,7 @@ Remark: for usage in a Svelte project, install `svelte-jsoneditor` instead.
4462
<div id="jsoneditor"></div>
4563

4664
<script type="module">
47-
import { JSONEditor } from 'vanilla-jsoneditor'
65+
import { JSONEditor } from 'vanilla-jsoneditor/standalone.js'
4866
4967
// Or use it through a CDN (not recommended for use in production):
5068
// import { JSONEditor } from 'https://unpkg.com/vanilla-jsoneditor/index.js'
@@ -84,7 +102,7 @@ Depending on whether you are using JavaScript of TypeScript, create either a JSX
84102

85103
### TypeScript:
86104

87-
```typescript
105+
```tsx
88106
//
89107
// JSONEditorReact.tsx
90108
//
@@ -126,7 +144,7 @@ export default JSONEditorReact
126144

127145
### JavaScript
128146

129-
```javascript
147+
```jsx
130148
//
131149
// JSONEditorReact.jsx
132150
//
@@ -172,7 +190,7 @@ If you are using NextJS, you will need to use a dynamic import to only render th
172190

173191
If you are using React in an conventional non-NextJS browser app, you can import the component using a standard import statement like `import JSONEditorReact from '../JSONEditorReact'`
174192

175-
```typescript
193+
```tsx
176194
//
177195
// demo.tsx for use with NextJS
178196
//
@@ -228,7 +246,7 @@ export default function Demo() {
228246
}
229247
```
230248

231-
```typescript
249+
```tsx
232250
//
233251
// TextContent.tsx
234252
//

‎README.md

+22-8
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,27 @@ Or one-way binding:
101101
</div>
102102
```
103103

104-
### Standalone bundle (use in React, Vue, Angular, plain JavaScript, ...)
104+
### Vanilla bundle (use in React, Vue, Angular, plain JavaScript, ...)
105105

106-
The library provides a standalone bundle of the editor via the npm library `vanilla-jsoneditor` (instead of `svelte-jsoneditor`) which can be used in any browser environment and framework. In a framework like React, Vue, or Angular, you'll need to write some wrapper code around the class interface.
106+
The library provides a vanilla bundle of the editor via the npm library `vanilla-jsoneditor` (instead of `svelte-jsoneditor`) which can be used in any browser environment and framework. In a framework like React, Vue, or Angular, you'll need to write some wrapper code around the class interface.
107107

108-
Note that the `vanilla-jsoneditor` package contains all dependencies. These are purely needed for the TypeScript types that they export.
108+
If you have a setup for your project with a bundler (like Vite, Rollup, or Webpack), it is best to use the default ES import:
109109

110-
Browser example loading the ES module:
110+
```ts
111+
// for use in a React, Vue, or Angular project
112+
import { JSONEditor } from 'vanilla-jsoneditor'
113+
```
114+
115+
If you want to use the library straight in the browser, use the provided standalone ES bundle:
116+
117+
```ts
118+
// for use directly in the browser
119+
import { JSONEditor } from 'vanilla-jsoneditor/standalone.js'
120+
```
121+
122+
The standalone bundle contains all dependencies of `vanilla-jsoneditor`, for example `lodash-es` and `Ajv`. If you use some of these dependencies in your project too, it means that they will be bundled twice in your web application, leading to a needlessly large application size. In general, it is preferable to use the default `import { JSONEditor } from 'vanilla-jsoneditor'` so dependencies can be reused.
123+
124+
Browser example loading the standalone ES module:
111125

112126
```html
113127
<!doctype html>
@@ -119,11 +133,11 @@ Browser example loading the ES module:
119133
<div id="jsoneditor"></div>
120134

121135
<script type="module">
122-
import { JSONEditor } from 'vanilla-jsoneditor'
136+
import { JSONEditor } from 'vanilla-jsoneditor/standalone.js'
123137
124138
// Or use it through a CDN (not recommended for use in production):
125-
// import { JSONEditor } from 'https://unpkg.com/vanilla-jsoneditor/index.js'
126-
// import { JSONEditor } from 'https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/index.js'
139+
// import { JSONEditor } from 'https://unpkg.com/vanilla-jsoneditor/standalone.js'
140+
// import { JSONEditor } from 'https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/standalone.js'
127141
128142
let content = {
129143
text: undefined,
@@ -180,7 +194,7 @@ Svelte component:
180194
JavasScript class:
181195

182196
```js
183-
import { JSONEditor } from 'vanilla-jsoneditor'
197+
import { JSONEditor } from 'vanilla-jsoneditor' // or 'vanilla-jsoneditor/standalone.js'
184198

185199
const content = { text: '[1,2,3]' }
186200

‎examples/browser/basic_usage.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<div id="jsoneditor"></div>
2121

2222
<script type="module">
23-
import { JSONEditor } from '../../package-vanilla/index.js'
23+
import { JSONEditor } from '../../package-vanilla/standalone.js'
2424

2525
// create the editor
2626
const editor = new JSONEditor({

‎examples/browser/custom_theme_color.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ <h1>JSONEditor with a custom theme color and large font</h1>
2727
<div id="my-jsoneditor"></div>
2828

2929
<script type="module">
30-
import { JSONEditor } from '../../package-vanilla/index.js'
30+
import { JSONEditor } from '../../package-vanilla/standalone.js'
3131

3232
const editor = new JSONEditor({
3333
target: document.getElementById('my-jsoneditor'),

‎examples/browser/json_schema_validation.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ <h1>JSON schema validation</h1>
3636
<div id="jsoneditor"></div>
3737

3838
<script type="module">
39-
import { JSONEditor, createAjvValidator } from '../../package-vanilla/index.js'
39+
import { JSONEditor, createAjvValidator } from '../../package-vanilla/standalone.js'
4040

4141
const schema = {
4242
title: 'Employee',

‎examples/browser/toggle_options.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<div id="jsoneditor"></div>
2929

3030
<script type="module">
31-
import { JSONEditor } from '../../package-vanilla/index.js'
31+
import { JSONEditor } from '../../package-vanilla/standalone.js'
3232

3333
const content = {
3434
text: undefined,

‎package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@
4141
"build:svelte:package-json": "node tools/createSveltePackageJson.js",
4242
"build:vanilla": "npm-run-all build:vanilla:**",
4343
"build:vanilla:clean": "del-cli package-vanilla",
44-
"build:vanilla:bundle": "rollup --config rollup.config.bundle.js",
45-
"build:vanilla:bundle-types": "rollup --config rollup.config.bundle-types.js",
44+
"build:vanilla:library": "rollup --config rollup.config.vanilla-library.js",
45+
"build:vanilla:bundle": "rollup --config rollup.config.vanilla-bundle.js",
46+
"build:vanilla:types": "rollup --config rollup.config.vanilla-types.js",
4647
"build:vanilla:copy:files": "cpy CHANGELOG.md LICENSE.md SECURITY.md package-vanilla",
4748
"build:vanilla:copy:readme": "cpy --rename README.md README-VANILLA.md package-vanilla",
4849
"build:vanilla:copy:themes": "cpy --flat src/lib/themes package-vanilla/themes",

‎rollup.config.vanilla-bundle.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import config from './rollup.config.vanilla-library.js'
2+
import path from 'path'
3+
4+
const packageFolder = 'package-vanilla'
5+
const file = path.join(packageFolder, 'standalone.js')
6+
7+
export default {
8+
...config,
9+
external: undefined,
10+
output: [
11+
{
12+
file,
13+
format: 'es',
14+
sourcemap: true,
15+
inlineDynamicImports: true
16+
}
17+
]
18+
}

‎rollup.config.bundle.js ‎rollup.config.vanilla-library.js

+2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import path from 'path'
77
import svelte from 'rollup-plugin-svelte'
88
import terser from '@rollup/plugin-terser'
99
import sveltePreprocess from 'svelte-preprocess'
10+
import { getVanillaDependencies } from './tools/getExternalDependencies.js'
1011

1112
const production = !process.env.ROLLUP_WATCH
1213
const packageFolder = 'package-vanilla'
1314
const file = path.join(packageFolder, 'index.js')
1415

1516
export default {
1617
input: 'src/lib/index.ts',
18+
external: getVanillaDependencies(),
1719
output: [
1820
{
1921
file,
File renamed without changes.

‎src/lib/components/modes/textmode/TextMode.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@
4343
highlightSpecialChars,
4444
keymap,
4545
lineNumbers,
46-
rectangularSelection,
47-
ViewUpdate
46+
rectangularSelection
4847
} from '@codemirror/view'
4948
import {
5049
defaultKeymap,
@@ -578,7 +577,7 @@
578577
EditorView.domEventHandlers({
579578
dblclick: handleDoubleClick
580579
}),
581-
EditorView.updateListener.of((update: ViewUpdate) => {
580+
EditorView.updateListener.of((update) => {
582581
editorState = update.state
583582
584583
if (update.docChanged) {

‎tools/createVanillaPackageJson.js

+7-28
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,16 @@
11
// create package.json and copy files like LICENSE.md to package-vanilla
22

33
import path from 'path'
4-
import assert from 'assert'
54
import { readFileSync, writeFileSync } from 'fs'
65
import { getAbsolutePath } from './utils/getAbsolutePath.mjs'
6+
import { getVanillaDependencies } from './getExternalDependencies.js'
77

88
const vanillaPackageFolder = getAbsolutePath(import.meta.url, '..', 'package-vanilla')
99

1010
const pkg = JSON.parse(String(readFileSync(getAbsolutePath(import.meta.url, '..', 'package.json'))))
11-
const typesPath = getAbsolutePath(import.meta.url, '..', 'package-vanilla', 'index.d.ts')
12-
const types = String(readFileSync(typesPath))
1311

14-
// scan the index.d.ts bundle file for all occurrences of "import { ...} from '...'" and extract the name
15-
const usedDependencyNames = uniq(
16-
Array.from(types.matchAll(/(import|export) .+ from '(.+)'/g))
17-
.map((match) => match[2])
18-
.sort()
19-
)
20-
const expectedDependencyNames = [
21-
'@fortawesome/free-solid-svg-icons',
22-
'ajv',
23-
'immutable-json-patch',
24-
'svelte'
25-
]
26-
27-
// We do not want to get surprises
28-
assert.deepStrictEqual(
29-
usedDependencyNames,
30-
expectedDependencyNames,
31-
`Used dependencies found in "${typesPath}" does not equal the expected dependencies. ` +
32-
'Please update the list in createVanillaPackageJson.js manually.'
33-
)
12+
// We add svelte here: this is needed to export the TypeScript types
13+
const usedDependencyNames = [...getVanillaDependencies(), 'svelte']
3414

3515
const usedDependencies = usedDependencyNames.reduce((deps, name) => {
3616
deps[name] = pkg.dependencies[name]
@@ -44,17 +24,16 @@ const vanillaPackage = {
4424
dependencies: usedDependencies, // needed for the TypeScript types
4525
devDependencies: {},
4626
svelte: undefined,
27+
browser: './standalone.js',
4728
exports: {
4829
...pkg.exports,
49-
'./index.js.map': './index.js.map'
30+
'./index.js.map': './index.js.map',
31+
'./standalone.js': './standalone.js',
32+
'./standalone.js.map': './standalone.js.map'
5033
}
5134
}
5235

5336
writeFileSync(
5437
path.join(vanillaPackageFolder, 'package.json'),
5538
JSON.stringify(vanillaPackage, null, 2)
5639
)
57-
58-
function uniq(array) {
59-
return [...new Set(array)]
60-
}

‎tools/develop-vanilla.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
JSONEditor,
108108
lodashQueryLanguage,
109109
jmespathQueryLanguage
110-
} from '../package-vanilla/index.js'
110+
} from '../package-vanilla/standalone.js'
111111

112112
const json = {
113113
array: [

‎tools/getExternalDependencies.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { readFileSync } from 'fs'
2+
import { getAbsolutePath } from './utils/getAbsolutePath.mjs'
3+
4+
// Get all dependencies for the vanilla package: dependencies that do not start with "svelte*"
5+
// (for example jsonrepair, lodash-es, ...)
6+
export function getVanillaDependencies() {
7+
const sveltePackageFolder = getAbsolutePath(import.meta.url, '..', 'package.json')
8+
9+
const pkg = JSON.parse(String(readFileSync(sveltePackageFolder)))
10+
return Object.keys(pkg.dependencies).filter((name) => !name.startsWith('svelte'))
11+
}

0 commit comments

Comments
 (0)
Please sign in to comment.