这就是我的目录的样子:
nicegui-codemirror-minimal/
├── dist/
│ └── codemirror-bundle.js
├── node_modules/
│ └── ...
├── codemirror_editor.js
├── codemirror_editor.py
├── main.py
├── package.json
├── package-lock.json
└── webpack.config.js
这是我的package.json
:
{
"name": "nicegui-codemirror-minimal-test",
"version": "1.0.0",
"description": "",
"main": "codemirror_editor.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@codemirror/commands": "^6.4.0",
"@codemirror/lang-markdown": "^6.2.4",
"@codemirror/merge": "^6.0.1",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.25.4",
"codemirror": "^6.0.1"
},
"devDependencies": {
"@babel/core": "^7.24.5",
"@babel/preset-env": "^7.24.5",
"babel-loader": "^9.1.3",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"vue": "^3.4.21"
}
}
这是我的
webpack.config.js
:
const path = require("path");
module.exports = {
entry: "./codemirror_editor.js",
mode: "development",
output: {
path: path.resolve(__dirname, "dist"),
filename: "codemirror-bundle.js",
library: "CodeMirrorEditor",
libraryTarget: "window",
globalObject: 'this',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
],
},
};
这是我的
codemirror_editor.js
:
import { EditorView, basicSetup } from "codemirror";
import { EditorState } from "@codemirror/state";
import { markdown } from "@codemirror/lang-markdown";
import { MergeView } from "@codemirror/merge";
import { keymap } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands";
import { nextTick } from 'vue';
export default {
template: `
<div style="display: flex; gap: 1em;">
<div ref="editorA" style="flex: 1; border: 1px solid #ddd;"></div>
<div ref="editorB" style="flex: 1; border: 1px solid #ddd;"></div>
</div>
`,
mounted() {
nextTick(() => {
setTimeout(() => {
const initialValueA = this.value_a || "";
const initialValueB = this.value_b || "";
this.mergeView = new MergeView({
a: {
doc: initialValueA,
extensions: [
basicSetup,
markdown(),
EditorView.editable.of(true),
keymap.of(defaultKeymap),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
this.sendUpdate('a', update.state.doc.toString());
}
})
],
},
b: {
doc: initialValueB,
extensions: [
basicSetup,
markdown(),
EditorView.editable.of(true),
keymap.of(defaultKeymap),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
this.sendUpdate('b', update.state.doc.toString());
}
}),
],
},
parent: this.$refs.editorA.parentElement,
root: document,
});
}, 0);
});
},
methods: {
sendUpdate(side, value) {
this.$emit('update-value', { side, value });
},
setValue(side, value) {
const editor = side === 'a' ? this.mergeView.a : this.mergeView.b;
const tr = editor.state.update({
changes: { from: 0, to: editor.state.doc.length, insert: value }
});
editor.dispatch(tr);
},
},
props: {
value_a: String,
value_b: String,
},
beforeDestroy() {
this.mergeView.destroy();
}
};
这是我的
codemirror_editor.py
:
from nicegui import ui
from typing import Callable, Optional
class CodeMirrorEditor(ui.element, component='codemirror_editor.js', dependencies=['dist/codemirror-bundle.js']):
def __init__(self,
value_a: str = "",
value_b: str = "",
on_change_a: Optional[Callable] = None,
on_change_b: Optional[Callable] = None
) -> None:
super().__init__()
self._props['value_a'] = value_a
self._props['value_b'] = value_b
self.on_change_a = on_change_a
self.on_change_b = on_change_b
self.on('update-value', self.handle_change)
def handle_change(self, event):
side = event.args['side']
value = event.args['value']
if side == 'a':
self._props['value_a'] = value
if self.on_change_a:
self.on_change_a(value)
elif side == 'b':
self._props['value_b'] = value
if self.on_change_b:
self.on_change_b(value)
self.update()
def set_value(self, side: str, value: str):
if side not in ('a', 'b'):
raise ValueError("side must be 'a' or 'b'")
self.run_method('setValue', side, value)
@property
def value_a(self) -> str:
return self._props['value_a']
@value_a.setter
def value_a(self, value: str) -> None:
self._props['value_a'] = value
self.set_value('a', value)
self.update()
@property
def value_b(self) -> str:
return self._props['value_b']
@value_b.setter
def value_b(self, value: str) -> None:
self._props['value_b'] = value
self.set_value('b', value)
self.update()
这是我的
main.py
:
from nicegui import ui
from codemirror_editor import CodeMirrorEditor
@ui.page('/')
async def page(): # Must be async
editor = CodeMirrorEditor(value_a="# Initial A", value_b="Initial B")
# That's it! No other UI elements or callbacks.
ui.run()
这就是我的浏览器的样子:浏览器图像带有错误
count某人可以帮助我理解为什么我会遇到此模块分辨率错误以及如何解决?我遵循了Nicegui文档进行节点模块集成,但是我显然缺少一些东西。关于WebPack配置,
codemirror_editor.js
中的模块导入或任何其他潜在问题的任何建议将不胜感激!
#########################因此,我已经意识到我的入口点可能是错误的,因为它指向
webpack.config.js
而不是
codemirror_editor.js
中的实际软件包(就像捆绑的节点集成示例中一样)。 同样,我尝试修改我的node_modules
不做codemirror_editor.js
,而是做import { MergeView } from "@codemirror/merge";
await import
正在将网络上传到我的网络中,
merge.js
以前,我只能看到codemirror_editor.js
codemirror_editor.js
显示404误差。控制台输出是以下(我的浏览器页面仍然为空白):get
Http://127.0.0.1:8080/dist/merge.jsNet:: err_aborted 404(找不到)
我相信这是因为在我的
merge.js
文件中,他们找不到我的
codemirror_editor.js
。我似乎不明白为什么。我也更简单,只安装了NPM。因此,基本上,如果我进行静态导入,我会发现相对路径问题,但是如果我等待进口,我会得到上述问题。,我的文件如下:这个是我的同一目录:
merge.js
这是我的@codemirror/merge
package.json
:
{
"scripts": {
"build": "webpack --config webpack.config.js"
},
"dependencies": {
"@codemirror/merge": "^6.0.1"
},
"devDependencies": {
"@babel/core": "^7.24.5",
"@babel/preset-env": "^7.24.5",
"babel-loader": "^9.1.3",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}
这是我的codemirror_editor.js
:
let mergeViewInstance;
export default async function createCodeMirrorEditor(element, props) {
const initialValueA = props.value_a || "";
const initialValueB = props.value_b || "";
// Dynamically import CodeMirror modules
const { MergeView } = await import("/dist/merge.js");
const { EditorView } = await import("/dist/view.js");
const { EditorState } = await import("/dist/state.js");
mergeViewInstance = new MergeView({
a: {
doc: initialValueA,
extensions: [
EditorView.editable.of(true),
// Removed other extensions for simplicity - you can add them back if needed
EditorView.updateListener.of((update) => {
if (update.docChanged) {
sendUpdate('a', update.state.doc.toString());
}
}),
],
},
b: {
doc: initialValueB,
extensions: [
EditorView.editable.of(true),
// Removed other extensions for simplicity - you can add them back if needed
EditorView.updateListener.of((update) => {
if (update.docChanged) {
sendUpdate('b', update.state.doc.toString());
}
}),
],
},
parent: element,
root: document,
});
function sendUpdate(side, value) {
element.dispatchEvent(new CustomEvent('update-value', { detail: { side, value } }));
}
function setValue(side, value) {
const editor = side === 'a' ? mergeViewInstance.a : mergeViewInstance.b;
const transaction = editor.state.update({
changes: { from: 0, to: editor.state.doc.length, insert: value }
});
editor.dispatch(transaction);
}
return {
setValue: setValue,
destroy: () => { mergeViewInstance.destroy(); }
};
}
这是我的
codemirror_editor.py
:
from nicegui import ui
from typing import Callable, Optional
class CodeMirrorEditor(ui.element, component='codemirror_editor.js', dependencies=[
'dist/merge.js',
'dist/view.js',
'dist/state.js',
]):
def __init__(self,
value_a: str = "",
value_b: str = "",
on_change_a: Optional[Callable] = None,
on_change_b: Optional[Callable] = None
) -> None:
super().__init__()
self._props['value_a'] = value_a
self._props['value_b'] = value_b
self.on_change_a = on_change_a
self.on_change_b = on_change_b
self.on('update-value', self.handle_change)
def handle_change(self, event):
side = event.args['detail']['side']
value = event.args['detail']['value']
if side == 'a':
self._props['value_a'] = value
if self.on_change_a:
self.on_change_a(value)
elif side == 'b':
self._props['value_b'] = value
if self.on_change_b:
self.on_change_b(value)
self.update()
def set_value(self, side: str, value: str):
if side not in ('a', 'b'):
raise ValueError("side must be 'a' or 'b'")
self.run_method('setValue', side, value)
@property
def value_a(self) -> str:
return self._props['value_a']
@value_a.setter
def value_a(self, value: str) -> None:
self._props['value_a'] = value
self.set_value('a', value)
self.update()
@property
def value_b(self) -> str:
return self._props['value_b']
@value_b.setter
def value_b(self, value: str) -> None:
self.props['value_b'] = value
self.set_value('b', value)
self.update()
我不熟悉python,但是当我运行此
example时,我发现了一个问题。 您应该预先编译所有必需的依赖项,例如:
webpack.config.js
此WebPack配置捆绑了CodeMirror模块,运行const path = require("path");
module.exports = {
entry: {
merge: "@codemirror/merge",
view: "@codemirror/view",
state: "@codemirror/state",
},
mode: "development",
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].js",
library: "CodeMirrorMerge",
libraryTarget: "umd",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
],
},
};
,然后您可以这样使用:
// webpack.config.js
const path = require("path");
module.exports = {
entry: "codemirror", // Search in the node_modules folder for modules
mode: "development",
output: {
path: path.resolve(__dirname, "dist"),
filename: "codemirror.js", // Bundled module file name
library: "codemirror", // Module name
libraryTarget: "umd",
},
// ...
};
该字段指定此组件所需的所有依赖关系,您现在可以在npm run build
.中使用codemirror。
发生了什么?答案在于生成的HTML内容。导航到DevTools网络选项卡,然后查看HTML内容 - 您会注意到它包含一个类似的字符串:
# codemirror_editor.py
from nicegui import ui
from typing import Callable, Optional
class CodeMirrorEditor(ui.element, component='codemirror_editor.js', dependencies=['dist/codemirror.js']):
# ...
这Playground(非功能,仅作为DIFF比较的参考)