observablehq / framework

A static site generator for data apps, dashboards, reports, and more. Observable Framework combines JavaScript on the front-end for interactive graphics with any language on the back-end for data analysis.
https://observablehq.com/framework/
ISC License
2.26k stars 97 forks source link

Preview Crash Due to Temporary Files Created by Vim #1498

Open jesusgollonet opened 1 month ago

jesusgollonet commented 1 month ago

Description:

When running npm run dev in one of the Observable examples, the engine frequently crashes. Upon investigation, I discovered that this issue is caused by Vim creating temporary files with a tilde (~) at the end, and then removing them. This triggers the engine to crash.

Steps to Reproduce

1.  Clone the repository and navigate to the example directory.
2.  Run npm install to install dependencies.
3.  Run npm run dev to start the preview.
4.  Edit any file in the project using Vim.
5.  Observe the engine crash when Vim creates and removes temporary files.

Expected Behavior:

The engine should handle the creation and removal of temporary files without crashing.

Actual Behavior:

The engine crashes whenever Vim creates and then removes temporary files with a tilde (~) at the end.

Environment:

•   OS: OsX Sonoma 14
•   Node.js version: 18
•   Observable framework version: 1.9.0

Additional Information:

It would be helpful to implement a mechanism to ignore temporary files created by text editors like Vim to prevent the engine from crashing during development.

Error Log

(note the ~ at the end of the file):

files: { removed: [], added: [] },
  tables: { removed: [], added: [] },
  stylesheets: { removed: [], added: [] },
  hash: {
    previous: '3cb45ab6f46b2e57f7e8da80f4cb9335fa5d7add83800cfc8555870c52ecb924',
    current: 'c098d0643d4f0858f7a1929094b1330fcf5fb8b442495d553437debec11586f7'
  }
}
node:fs:1690
  handleErrorFromBinding(ctx);
  ^

Error: ENOENT: no such file or directory, stat 'src/test.md~'
    at statSync (node:fs:1690:3)
    at visitFiles (file:///Users/jgb/Sketch/2024-07-01_19.39.22_observable-tutorial/hello-framework/node_modules/.pnpm/@observablehq+framework@1.9.0_@types+markdown-it@14.1.1/node_modules/@observablehq/framework/dist/files.js:37:20)
    at visitFiles.next (<anonymous>)
    at visitMarkdownFiles (file:///Users/jgb/Sketch/2024-07-01_19.39.22_observable-tutorial/hello-framework/node_modules/.pnpm/@observablehq+framework@1.9.0_@types+markdown-it@14.1.1/node_modules/@observablehq/framework/dist/files.js:27:14)
    at visitMarkdownFiles.next (<anonymous>)
    at readPages (file:///Users/jgb/Sketch/2024-07-01_19.39.22_observable-tutorial/hello-framework/node_modules/.pnpm/@observablehq+framework@1.9.0_@types+markdown-it@14.1.1/node_modules/@observablehq/framework/dist/config.js:42:14)
    at Object.get [as pages] (file:///Users/jgb/Sketch/2024-07-01_19.39.22_observable-tutorial/hello-framework/node_modules/.pnpm/@observablehq+framework@1.9.0_@types+markdown-it@14.1.1/node_modules/@observablehq/framework/dist/config.js:122:57)
    at watcher (file:///Users/jgb/Sketch/2024-07-01_19.39.22_observable-tutorial/hello-framework/node_modules/.pnpm/@observablehq+framework@1.9.0_@types+markdown-it@14.1.1/node_modules/@observablehq/framework/dist/preview.js:280:55) {
  errno: -2,
  syscall: 'stat',
  code: 'ENOENT',
  path: 'src/test.md~'
}
jesusgollonet commented 1 month ago

I of course can make vim not generate those files, but I have never had to do that before.

Raising because I got this issue yesterday while trying framework for the first time and the constant crashes made me almost give up on it. And I would have missed out!

A naive attempt that seems to fix this is to just ignore files that end with tilde in visitFiles, as they are quite likely backup files from vim. I quickly tried on the generated js code and crashes stopped. Haven't checked if this affects anything else.

function* visitFiles(root) {
  const visited = /* @__PURE__ */ new Set();
  const queue = [root = normalize(root)];
  for (const path of queue) {
     if (path.lastIndexOf('~') > -1){
        continue;
    }
    const status = statSync(path);
    if (status.isDirectory()) {
      if (visited.has(status.ino))
        continue;
...