Open3

nextjsのquillの実装に対する調査

kamaguchikamaguchi

import Quill from "quill";

この場合の実装にするケースでは、以下のようになる。

<div  ref={(node) => {
    if ( typeof window === 'object' && editorRef.current && !quillRef.current) {
        quillRef.current = new Quill(editorRef.current, {
            theme: "snow",
            modules: {
                toolbar: [
                    [{ header: [1, 2, 3, false] }],
                    ["bold", "italic", "underline", "strike"],
                    [{ list: "ordered" }, { list: "bullet" }],
                    ["blockquote", "code-block"],
                    [{ align: [] }],
                    [{ color: [] }, { background: [] }],
                    [
                        "link",
                        // "image"
                    ],
                    ["clean"],
                ],
            },
        });
        if (item?.detail) {
            quillRef.current.clipboard.dangerouslyPasteHTML(item.detail);
        }
    }
}} />
 ⨯ ReferenceError: document is not defined
    at Array.forEach (<anonymous>)
    at (ssr)/./node_modules/quill/core/emitter.js (.next/server/vendor-chunks/quill.js:140:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at (ssr)/./node_modules/quill/core/selection.js (.next/server/vendor-chunks/quill.js:190:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at (ssr)/./node_modules/quill/core/editor.js (.next/server/vendor-chunks/quill.js:130:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at (ssr)/./node_modules/quill/core/quill.js (.next/server/vendor-chunks/quill.js:180:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at (ssr)/./node_modules/quill/core.js (.next/server/vendor-chunks/quill.js:110:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at (ssr)/./node_modules/quill/quill.js (.next/server/vendor-chunks/quill.js:560:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(ssr)/./src/components/parts/CMemoryTaskEdit.tsx:12:63)
    at (ssr)/./src/components/parts/CMemoryTaskEdit.tsx (.next/server/app/memoryTask/page.js:465:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(ssr)/./src/components/SectionMemoryTask.tsx:11:80)
    at (ssr)/./src/components/SectionMemoryTask.tsx (.next/server/app/memoryTask/page.js:421:1)
    at Object.__webpack_require__ [as require] (.next/server/webpack-runtime.js:33:43) {
  digest: '3264658594'
}
 GET /memoryTask 500 in 377ms
kamaguchikamaguchi

調査対象に対する因子では、機械学習で以下を確認された。
2時間程度の調査プロセスに対して、実装へのパタンが3つ程度を考慮したが、機械学習から提供されるコードの方が前提知識が多い。

なお、以下の実装に対してもアプローチしている。

useEffect(() => {
    if (typeof window !== "undefined") {
      import("quill").then((QuillModule) => {
        setQuill(QuillModule.default ?? QuillModule);
      });
    }
  }, []);

	useEffect(() => {
    if (Quill && editorRef.current && !quillRef.current) {
      import("quill").then((Quill) => {
        quillRef.current = new Quill.default(editorRef.current!, {
          theme: "snow",
            modules: {
                toolbar: [
                    [{ header: [1, 2, 3, false] }],
                    ["bold", "italic", "underline", "strike"],
                    [{ list: "ordered" }, { list: "bullet" }],
                    ["blockquote", "code-block"],
                    [{ align: [] }],
                    [{ color: [] }, { background: [] }],
                    [
                        "link",
                        // "image"
                    ],
                    ["clean"],
                ],
            },
        });

        if (item?.detail) {
          quillRef.current.clipboard.dangerouslyPasteHTML(item.detail);
        }
      });
    }
  }, [Quill, item?.detail]);
kamaguchikamaguchi

認知付加をかけるためのコードの内容に対して、コードへのプロセスをどこのハイドレーションで、レンダリング構造なのかをdomのライフサイクルをベースに発想していく前提ではあるが、ssrの実装に対しての検証を判断基準へ対処するためアプローチを考慮する必要がある。

なお、現状ではquillのuiが1度のレンダリングに対して2個が表示されており、最終的には以下のコードになった。

useEffect( () => {
		if (editorRef.current && !quillRef.current) {
			import("quill").then((Quill) => {
				if(quillCounter === 0) {
					quillRef.current = new Quill.default(editorRef.current!, {
						theme: "snow",
						modules: {
							toolbar: [
								[{ header: [1, 2, 3, false] }],
								["bold", "italic", "underline", "strike"],
								[{ list: "ordered" }, { list: "bullet" }],
								["blockquote", "code-block"],
								[{ align: [] }],
								[{ color: [] }, { background: [] }],
								[
									"link",
									// "image"
								],
								["clean"],
							],
						},
					});
					quillCounterSet(1);
				}
				let isStyleApplied = false;

				const applyStyleOnce = () => {
          const targetDom = editorBoxRef.current?.querySelector(".ql-toolbar");
					console.log(targetDom);
          
          if (targetDom && !isStyleApplied) {
            targetDom.setAttribute("style", "display:none;");
            isStyleApplied = true;
            
            if (item?.detail) {
              quillRef.current?.clipboard.dangerouslyPasteHTML(item.detail);
            }
            
            quillCounterSet(1);
            return;
          }
          
          if (!isStyleApplied) {
            requestAnimationFrame(applyStyleOnce);
          }
        };
        
        requestAnimationFrame(applyStyleOnce);

				if (item?.detail) {
					quillRef.current?.clipboard.dangerouslyPasteHTML(item.detail);
				}
			});
		}

	},[item?.detail]);