@berlysia/vertical-writing-slide-system 0.0.10 → 0.0.12

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/cli.js CHANGED
@@ -30,9 +30,13 @@ async function runBuildAll() {
30
30
  async function runBuild() {
31
31
  try {
32
32
  await build({
33
- root: resolve(import.meta.dirname),
33
+ root: process.cwd(),
34
+ configFile: resolve(import.meta.dirname, "vite.config.ts"),
34
35
  build: {
35
- outDir: resolve("pages"),
36
+ outDir: resolve(process.cwd(), "pages"),
37
+ rollupOptions: {
38
+ input: resolve(import.meta.dirname, "src/main.tsx"),
39
+ },
36
40
  },
37
41
  });
38
42
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berlysia/vertical-writing-slide-system",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "vertical-slides": "./cli.js"
@@ -1,11 +1,11 @@
1
1
  import { existsSync } from "fs";
2
- import { mkdir, readdir, stat, cp, writeFile, mkdtemp, rmdir, } from "fs/promises";
2
+ import { mkdir, readdir, stat, cp, writeFile, mkdtemp, rm } from "fs/promises";
3
3
  import { join, resolve } from "path";
4
4
  import { build } from "vite";
5
5
  const defaultSlidesDir = resolve(import.meta.dirname, "..", "slides");
6
6
  const pagesDir = "pages";
7
7
  // Ensure pages directory exists
8
- await rmdir(pagesDir, { recursive: true });
8
+ await rm(pagesDir, { recursive: true });
9
9
  await mkdir(pagesDir, { recursive: true });
10
10
  async function buildSlide(slideName) {
11
11
  console.log(`Building ${slideName}...`);
@@ -20,7 +20,7 @@ async function buildSlide(slideName) {
20
20
  const slideOutputDir = join(pagesDir, slideName);
21
21
  await mkdir(slideOutputDir, { recursive: true });
22
22
  await cp(tmpDir, slideOutputDir, { recursive: true });
23
- await rmdir(tmpDir, { recursive: true });
23
+ await rm(tmpDir, { recursive: true });
24
24
  }
25
25
  async function createIndexPage(slideNames) {
26
26
  const slides = slideNames
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "unified";
2
2
  import { visit } from "unist-util-visit";
3
- import type { Root } from "mdast";
3
+ import type { Root, Image } from "mdast";
4
4
 
5
5
  interface RemarkSlideImagesOptions {
6
6
  base: string;
@@ -12,17 +12,22 @@ const remarkSlideImages: Plugin<[RemarkSlideImagesOptions], Root> = (
12
12
  const { base } = options;
13
13
 
14
14
  return (tree) => {
15
- visit(tree, (node: any) => {
15
+ visit(tree, (node) => {
16
16
  // Handle Markdown image syntax
17
- if (node.type === "image" && typeof node.url === "string") {
18
- if (node.url.startsWith("@slide/")) {
19
- node.url = `${base}slide-assets/images/${node.url.slice(7)}`;
17
+ if (node.type === "image") {
18
+ const imageNode = node as Image;
19
+ if (imageNode.url.startsWith("@slide/")) {
20
+ imageNode.url = `${base}slide-assets/images/${imageNode.url.slice(7)}`;
20
21
  }
21
22
  }
22
23
 
23
24
  // Handle MDX JSX img elements
24
- if (node.type === "mdxJsxFlowElement" && node.name === "img") {
25
- const src = node.attributes?.find(
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ if (node.type === "mdxJsxFlowElement" && (node as any).name === "img") {
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ const mdxNode = node as any;
29
+ const src = mdxNode.attributes?.find(
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
31
  (attr: any) => attr.type === "mdxJsxAttribute" && attr.name === "src",
27
32
  );
28
33
  if (
@@ -36,9 +41,11 @@ const remarkSlideImages: Plugin<[RemarkSlideImagesOptions], Root> = (
36
41
 
37
42
  // Handle HTML img tags in Markdown
38
43
  if (node.type === "html") {
39
- const value = node.value as string;
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const htmlNode = node as any;
46
+ const value = htmlNode.value as string;
40
47
  if (value.startsWith("<img")) {
41
- node.value = value.replace(
48
+ htmlNode.value = value.replace(
42
49
  /<img\s+([^>]*src="(@slide\/[^"]+)"[^>]*)>/g,
43
50
  (_, attributes, src) => {
44
51
  return `<img ${attributes.replace(
@@ -50,7 +50,7 @@ function validateSlidesDir(dir: string): void {
50
50
  }
51
51
  try {
52
52
  fs.accessSync(dir, fs.constants.R_OK);
53
- } catch (err) {
53
+ } catch {
54
54
  throw new Error(`No read permission for external slides directory: ${dir}`);
55
55
  }
56
56
  }
@@ -149,10 +149,12 @@ export default async function slidesPlugin(
149
149
 
150
150
  let base: string;
151
151
  let compiledSlides: string[] = [];
152
+ let resolvedConfig: ResolvedConfig;
152
153
  return {
153
154
  name: "vite-plugin-slides",
154
155
  configResolved(config: ResolvedConfig) {
155
156
  base = config.base;
157
+ resolvedConfig = config;
156
158
  },
157
159
  enforce: "pre",
158
160
  resolveId(id: string) {
@@ -169,7 +171,7 @@ export default async function slidesPlugin(
169
171
  nullPrefixedVirtualFilePageIdPattern.test(id)
170
172
  ) {
171
173
  return {
172
- code: `import React from 'react';\n${code}`,
174
+ code: `import * as React from 'react';\n${code}`,
173
175
  map: null,
174
176
  };
175
177
  }
@@ -220,6 +222,8 @@ export default async function slidesPlugin(
220
222
  const result = await compile(slideContent, {
221
223
  outputFormat: "program",
222
224
  development: false,
225
+ jsxImportSource: "react",
226
+ jsxRuntime: "automatic",
223
227
  remarkPlugins: [[remarkSlideImages, { base }]],
224
228
  });
225
229
  return result.value as string;
@@ -282,35 +286,134 @@ export default async function slidesPlugin(
282
286
  }
283
287
  },
284
288
  async buildStart() {
285
- const targetImagesDir = path.resolve(
286
- process.cwd(),
287
- "public/slide-assets/images",
288
- );
289
- const sourceImagesDir = path.resolve(
290
- config.slidesDir,
291
- config.collection,
292
- "images",
293
- );
294
-
295
- // Copy images from slides directory
296
- if (fs.existsSync(sourceImagesDir)) {
297
- try {
298
- // Create target directory if it doesn't exist
299
- mkdirSync(targetImagesDir, { recursive: true });
300
-
301
- // Copy all files from source to target
302
- const imageFiles = readdirSync(sourceImagesDir);
303
- for (const file of imageFiles) {
304
- const sourcePath = path.join(sourceImagesDir, file);
305
- const targetPath = path.join(targetImagesDir, file);
306
- copyFileSync(sourcePath, targetPath);
289
+ // Handle images during dev mode
290
+ if (resolvedConfig.command === "serve") {
291
+ const targetImagesDir = path.resolve(
292
+ resolvedConfig.root,
293
+ "public/slide-assets/images",
294
+ );
295
+ const sourceImagesDir = path.resolve(
296
+ config.slidesDir,
297
+ config.collection,
298
+ "images",
299
+ );
300
+
301
+ // Copy images from slides directory
302
+ if (fs.existsSync(sourceImagesDir)) {
303
+ try {
304
+ // Create target directory if it doesn't exist
305
+ mkdirSync(targetImagesDir, { recursive: true });
306
+
307
+ // Copy all files from source to target
308
+ const imageFiles = readdirSync(sourceImagesDir);
309
+ for (const file of imageFiles) {
310
+ const sourcePath = path.join(sourceImagesDir, file);
311
+ const targetPath = path.join(targetImagesDir, file);
312
+ copyFileSync(sourcePath, targetPath);
313
+ }
314
+ logger.info("Copied slide images successfully");
315
+ } catch (error) {
316
+ if (error instanceof Error) {
317
+ logger.error("Failed to copy slide images", error);
318
+ }
319
+ throw error;
307
320
  }
308
- logger.info("Copied slide images successfully");
309
- } catch (error) {
310
- if (error instanceof Error) {
311
- logger.error("Failed to copy slide images", error);
321
+ }
322
+ }
323
+ },
324
+
325
+ generateBundle(options, bundle) {
326
+ // Generate HTML file if none exists in consumer project
327
+ const consumerIndexHtml = path.resolve(resolvedConfig.root, "index.html");
328
+
329
+ if (!fs.existsSync(consumerIndexHtml)) {
330
+ // Find the main JS file in the bundle
331
+ const mainJsFile = Object.keys(bundle).find(
332
+ (fileName) =>
333
+ fileName.startsWith("assets/main-") && fileName.endsWith(".js"),
334
+ );
335
+
336
+ if (!mainJsFile) {
337
+ logger.error("Could not find main JS file in bundle");
338
+ return;
339
+ }
340
+
341
+ const virtualIndexHtml = `<!doctype html>
342
+ <html lang="ja">
343
+ <head>
344
+ <meta charset="UTF-8" />
345
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
346
+ <title>Vertical Writing Slides</title>
347
+ <link rel="preconnect" href="https://fonts.googleapis.com">
348
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
349
+ <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&family=Noto+Sans+Mono:wght@100..900&display=swap" rel="stylesheet">
350
+ </head>
351
+ <body>
352
+ <div id="root"></div>
353
+ <script type="module" src="./${mainJsFile}"></script>
354
+ </body>
355
+ </html>`;
356
+
357
+ // Emit HTML file as part of the build output
358
+ this.emitFile({
359
+ type: "asset",
360
+ fileName: "index.html",
361
+ source: virtualIndexHtml,
362
+ });
363
+
364
+ logger.info("Generated index.html for build output");
365
+ }
366
+
367
+ // Handle images during build mode
368
+ if (resolvedConfig.command === "build") {
369
+ const sourceImagesDir = path.resolve(
370
+ config.slidesDir,
371
+ config.collection,
372
+ "images",
373
+ );
374
+
375
+ if (fs.existsSync(sourceImagesDir)) {
376
+ try {
377
+ const imageFiles = readdirSync(sourceImagesDir);
378
+ logger.info(
379
+ `Processing ${imageFiles.length} image files from ${sourceImagesDir}`,
380
+ );
381
+
382
+ let processedCount = 0;
383
+ for (const file of imageFiles) {
384
+ const sourcePath = path.join(sourceImagesDir, file);
385
+ try {
386
+ const imageContent = fs.readFileSync(sourcePath);
387
+
388
+ // Add image files to the bundle
389
+ this.emitFile({
390
+ type: "asset",
391
+ fileName: `slide-assets/images/${file}`,
392
+ source: imageContent,
393
+ });
394
+ processedCount++;
395
+ logger.info(`Added image to bundle: ${file}`);
396
+ } catch (fileError) {
397
+ logger.error(
398
+ `Failed to process image file: ${file}`,
399
+ fileError instanceof Error
400
+ ? fileError
401
+ : new Error(String(fileError)),
402
+ );
403
+ // Continue processing other files instead of failing completely
404
+ }
405
+ }
406
+ logger.info(
407
+ `Successfully added ${processedCount}/${imageFiles.length} slide images to bundle`,
408
+ );
409
+ } catch (error) {
410
+ if (error instanceof Error) {
411
+ logger.error("Failed to read slide images directory", error);
412
+ }
413
+ throw error;
312
414
  }
313
- throw error;
415
+ } else {
416
+ logger.warn(`No images directory found at: ${sourceImagesDir}`);
314
417
  }
315
418
  }
316
419
  },
package/vite.config.ts CHANGED
@@ -9,7 +9,10 @@ export default defineConfig(async () => {
9
9
  base: "./",
10
10
  resolve: {
11
11
  alias: {
12
- "@components": "/src/slide-components",
12
+ "@components": path.resolve(
13
+ import.meta.dirname,
14
+ "src/slide-components",
15
+ ),
13
16
  },
14
17
  },
15
18
  plugins: [