-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
minista v4 開発メモ #121
Comments
初期メモテーマ:軽量化と互換性
「ministaの機能はぜんぶViteプラグインになりました!」という感じにしたい。理由は以下の通り。
裏でむちゃくちゃやってる部分をViteプラグイン化できるかわからない部分もあるし、密結合な機能を分割できるかもわからないけど、試しに作ってみたら結構上手くいったので進めてみる。
いくつかプラグインを作って命名規則がしっくりきたらブランチに上げる。 v3はsharpがBunで動かなくてコケてたけどリポジトリには改善されたと書いてあったのでもう一度試す。動かなくてもプラグインを分割するので問題を切り離せる。 |
エンハンスプラグインの利用シーンイメージ import html from "./index.html?raw"
function ComponentBox() {
return (
<div className="box">
<p>component text</p>
</div>
)
}
export default function (): EnhancePage {
return {
html,
commands: [
{
selector: "section#content3 > div",
component: ComponentBox,
},
],
}
}
|
エンハンスプラグインはReact componentをHTMLとして挿入できるだけでなく、HTMLの挿入、要素の削除、attributeの修正や正規表現を使った既存の値のreplaceなども行えるようにした。 export default function (): EnhancePage {
return {
html,
commands: [
{
selector: "html",
attr: "lang",
value: "ja",
},
{
selector: `link[href="/css/style2.css"]`,
method: "remove",
},
{
selectorAll: "script",
attr: "src",
pattern: /^\/(.*?)/,
value: "https://example.com/$1",
},
{
selector: "section#content1 > div",
html: `<div class="box"><p>html text</p></div>`,
},
],
}
} |
minista-plugin-appの予定だったものはminista-plugin-mpaに変更。appだとディレクトリ名がassetsより上に来てしまう。
|
プラグインを同時に使用する場合は、ページパスの重複を避けるため拡張子を追加して同居させるのが望ましい。
|
アルファ版をリリースした。実務で検証を開始。 |
エンハンス用立ち上げインストール。 npm i -D minista@next minista-plugin-enhance@next vite react react-dom typescript @types/react @types/react-dom |
StoryApp用 npm i react react-dom npm i -D minista@next vite typescript @types/node @types/react @types/react-dom npm i -D minista-plugin-enhance@next minista-plugin-entry@next minista-plugin-mdx@next minista-plugin-story@next minista-plugin-beautify@next minista-plugin-archive@next |
エンハンスプラグインで無茶苦茶編集すると最終的に何ができあがっているのかイメージしづらくなった。編集箇所を決めること、全体処理とコンポーネントの差し込みをメインにして、基本的な作業はコンポーネント側に渡す方が良さそう。全体リニューアルには向かない。 |
StoryAppにローディングアニメーションを追加する。 NetlifyにアップしたプロトタイプはTTFBがかなり遅くて長いHTMLのロードに数秒時間がかかっている。パスの先が無くてエラーを起こしているのかロード中なのか不明でストレス。 すぐにロードできている場合は出さない。2〜3秒かかった場合にローディングを出すようにしてみる。
|
minista-plugin-deliveryの機能は最近使ってないから一旦削除でいいかも。storyapp使って納品してる。ただ、実機スマホで見てもらうなどの用途の時にないと困る可能性はある。 |
minista-plugin-island babelのparse, traverse, generateを使ってIslandコンポーネント配下を検出しようとしたがesmでうまく動かず。
// defaultを使う形でも動かない?
import traverse from "@babel/traverse"
traverse.default(...) |
#122 の画像生成キャッシュを導入する。 |
Partial Hydrationの動作するReactのバージョンを18以上に変更した。
|
Partial HydrationのusePreactオプションを削除した。
今後は手動でpreact-compatをビルド全体に対して設定することにする。これによりプラグインの影響範囲を超えることを認識する。 |
MPAプラグインは使わなそうなので予定から一旦削除。 |
vituumを参考にSSGプラグインを新しい方法で作ってみたが、coreのHTMLプラグインの挙動をいじれない部分があり破棄。 このプラグインではHTMLファイルを実際に生成してViteのinputに渡す。既存のemitFileで生成結果を差し込む場合と異なり、srcやhrefでルートパスを書いたアセットを簡単にバンドルできる。 ただし、エントリーのスクリプトに不要な内容が含まれたり、エントリーしたCSSの名前やタグの順番が変わったりと実務に向かなかった。 import type { Plugin, UserConfig } from "vite"
import fs from "node:fs"
import path from "node:path"
import fg from "fast-glob"
import type { SsgPage } from "minista-shared-utils"
import {
checkDeno,
getCwd,
getPluginName,
getTempName,
getRootDir,
getTempDir,
getHtmlPath,
getBasedAssetPath,
} from "minista-shared-utils"
import type { ImportedLayouts, ImportedPages } from "../@types/node.js"
import type { PluginOptions } from "./option.js"
import { getGlobExportCode, getSsgExportCode } from "./code.js"
import { formatLayout, resolveLayout } from "./layout.js"
import { formatPages, resolvePages } from "./page.js"
import { transformHtml } from "./html.js"
export function pluginSsgBuild(opts: PluginOptions): Plugin {
const isDeno = checkDeno()
const cwd = getCwd(isDeno)
const names = ["ssg", "build"]
const pluginName = getPluginName(names)
const tempName = getTempName(names)
const regCwd = new RegExp("^" + cwd)
let isSsr = false
let base = "/"
let rootDir = ""
let tempDir = ""
let globDir = ""
let globFile = ""
let ssrDir = ""
let ssrFile = ""
let ssgDir = ""
let entries: { [key: string]: string } = {}
let entryChanges: {
beforeName: string
afterName: string
}[] = []
return {
name: pluginName,
enforce: "post",
apply: "build",
config: async (config, { command }) => {
isSsr = config.build?.ssr ? true : false
base = config.base || base
rootDir = getRootDir(cwd, config.root || "")
tempDir = getTempDir(cwd, rootDir)
globDir = path.join(tempDir, "glob")
globFile = path.join(globDir, `${tempName}.js`)
ssrDir = path.join(tempDir, "ssr")
ssrFile = path.join(ssrDir, `${tempName}.mjs`)
ssgDir = path.join(tempDir, "ssg")
if (isSsr) {
const code = getGlobExportCode(opts)
await fs.promises.mkdir(globDir, { recursive: true })
await fs.promises.writeFile(globFile, code, "utf8")
return {
build: {
rollupOptions: {
input: {
[tempName]: globFile,
},
output: {
chunkFileNames: "[name].mjs",
entryFileNames: "[name].mjs",
},
},
outDir: ssrDir,
},
ssr: {
external: ["minista-shared-head"],
},
} as UserConfig
}
if (!isSsr) {
const htmlFiles = await fg(path.join(ssgDir, `**/*.html`))
const regRootDirSlash = new RegExp("^" + rootDir + "[/\\\\]")
const redSsgDirSlash = new RegExp("^" + ssgDir + "[/\\\\]")
for (const htmlFile of htmlFiles) {
const htmlKey = htmlFile
.replace(regCwd, "")
.replace(/\//g, "_")
.replace(/\\/g, "_")
.replace(/\./g, "_")
entries[htmlKey] = htmlFile
const beforeName = htmlFile.replace(regRootDirSlash, "")
const afterName = htmlFile.replace(redSsgDirSlash, "")
entryChanges.push({ beforeName, afterName })
}
//console.log("entryChanges: ", entryChanges)
return {
build: {
rollupOptions: {
input: entries,
},
},
}
}
},
generateBundle(options, bundle) {
if (!isSsr) {
const diffDir = path.relative(ssgDir, rootDir)
const upDirCount = diffDir
.split(/[/\\]/)
.filter((part) => part === "..").length
const upDirString = "../".repeat(upDirCount)
//console.log("generateBundle: ", bundle)
for (const entryChange of entryChanges) {
const { beforeName, afterName } = entryChange
if (bundle[beforeName]) {
bundle[beforeName].fileName = afterName
}
}
//console.log("generateBundle: ", bundle)
}
},
async writeBundle(options, bundle) {
if (isSsr) {
const { LAYOUTS, PAGES } = (await import(ssrFile)) as {
LAYOUTS: ImportedLayouts
PAGES: ImportedPages
}
const formatedLayout = formatLayout(LAYOUTS)
const resolvedLayout = await resolveLayout(formatedLayout)
const formatedPages = formatPages(PAGES, opts)
const resolvedPages = await resolvePages(formatedPages)
const ssgPages = resolvedPages.map((resolvedPage) => {
const fileName = getHtmlPath(resolvedPage.path)
const html = transformHtml({ resolvedLayout, resolvedPage })
return { fileName, html }
})
await Promise.all(
ssgPages.map(async (ssgPage) => {
const filePath = path.join(ssgDir, ssgPage.fileName)
const fileDir = path.dirname(filePath)
const code = ssgPage.html
await fs.promises.mkdir(fileDir, { recursive: true })
await fs.promises.writeFile(filePath, code, "utf8")
})
)
}
},
}
} |
plugin-bundleとplugin-entryのHTML処理が重複するためplugin-bundleに統合する。画像のsrcエントリーにも対応。plugin-ssgに含まれる画像の相対パスに関する修正もplugin-bundleに移動する。
|
Releases
テーマ:モジュラー化
Features
Breaking Changes
Plans
開発ブランチ: v4
Packages
Tasks
The text was updated successfully, but these errors were encountered: