eleventy icon indicating copy to clipboard operation
eleventy copied to clipboard

Issues with watching JS dependencies declared in configuration

Open zachleat opened this issue 5 years ago • 10 comments

Filed via @anandchowdhary

image

https://github.com/11ty/eleventy/issues/701#issuecomment-575613848

zachleat avatar Jul 11 '20 02:07 zachleat

Following up on this discussion from Discord : https://discordapp.com/channels/741017160297611315/741017160297611319/757230379202773002

The issue at hand on Discord is in a JS template, but I think it is the exact same issue mentioned here. The "DeleteRequireCache" utility should probably delete the Module children cache entries also, using require.cache[normalizedPath].children in a recursive loop here : https://github.com/11ty/eleventy/blob/330191c10b9ab4b93a3abcf6406bbc350a47aa7d/src/Util/DeleteRequireCache.js#L8-L11

I could get a PR together, just checking for a green light and if such a fix is not already in the pipeline.

AurelienStebe avatar Sep 20 '20 15:09 AurelienStebe

@AurelienStebe Did you develop a solution or workaround for this? I'm having a few issues with changes to required JS files not triggering a refresh (or in some cases requiring that I restart the server). I'm seeing it with files required in the config, and files required in layouts.

esharri2 avatar Jan 02 '21 20:01 esharri2

No, this was just a drive-by bug fix. I had the exact same issue in my own project the week before, so I knew the solution.

It should really just need a few lines of code : before deleting the module itself from the require cache, just loop on its children and call the function recursively. Unfortunately, it needs to be fixed in this very file in Eleventy, I don't think you can do much from outside (apart from deleting the whole cache maybe, but that's about the same as restarting the process). This should make sure that dependencies of dependencies are re-read from disk in "live" mode, however I don't know if they are all "watched" correctly (but there is eleventyConfig.addWatchTarget() for that).

I thought work was being done on the "--watch" mode and incremental builds, so I didn't move forward at the time.

AurelienStebe avatar Jan 03 '21 23:01 AurelienStebe

Yeah I just hit the same problem. Any dependencies of an .11ty.js layout are not correctly updated when the page reloads. This makes it almost impossible to work with JS templates :/

I tried the recursive cache deletion of children suggested above but it doesn't seem to help. I've never really played with Node's cache before so I probably messed it up 😓

The easiest workaround I've found is to just inline all my components and helpers into the layout file for now, so I don't have to require anything...

oliverjam avatar Jan 14 '21 16:01 oliverjam

@zachleat is this in the pipeline or worth me getting a PR together?

tomglynch avatar Feb 18 '21 01:02 tomglynch

I tried the recursive cache deletion of children suggested above but it doesn't seem to help. I've never really played with Node's cache before so I probably messed it up

Same here. Couldn't get it to work either. @oliverjam could you post your code and I'll give it a run?

tomglynch avatar Feb 19 '21 03:02 tomglynch

For those using js templates, one workaround is to manually require your js files and not calling shortcode with this.

You loose access to data pages but hot reloading is working.

Weird : dependencies in layout files are not reloading.

seb-celinedesign avatar Feb 28 '21 19:02 seb-celinedesign

I had a similar issue where the page would hot reload but any changes made to includes were not being made in the rendered copy (unless I restarted eleventy via the command line).

I was able to resolve the issue by making sure chokidar was installed and watch: true was set in the FileSystemLoader options in my .eleventy.js file:

const nunjucksEnvironment = new Nunjucks.Environment(
  new Nunjucks.FileSystemLoader("src/includes", { watch: true })
);

ZachSaucier avatar Mar 27 '21 13:03 ZachSaucier

Hi, are there any solutions on this bug right now?

cnoss avatar Oct 13 '21 07:10 cnoss

Just popping in here to say I'm running into the same issue on WSL2 with JS dependencies inside of my .11ty.js templates. 11ty seems to pick up the changes, but the output remains the original cached content.

Editing to say that manually requiring my JS layout files in the JS templates that call them seems to have fixed the issue as far as I can tell.

JoshBeveridge avatar Sep 19 '22 15:09 JoshBeveridge

Shipping #2479 with 2.0.0-canary.18—would love a retest after the next canary ships! (and thank you to @Snapstromegon!)

zachleat avatar Nov 18 '22 19:11 zachleat

Closing as the PR was shipped!

zachleat avatar Dec 07 '22 19:12 zachleat

Hey @zachleat, I'm noticing this issue all over again on 2.0.1 using the new dev server on WSL2.

I have the following directory structure:

src
  _includes
    components
      component.11ty.js
    layouts
      layout.11ty.js
  content
    index.11ty.js

Where index pulls layout via data { layout: 'layouts/layout.11ty.js' }, and layout requires component.

Updating component triggers 11ty to build, but the refreshed page doesn't display the changes. I'm forced to save layout twice, which then reflects the changes in component. Oddly enough, saving index doesn't trigger the changes either...

I'm assuming https://github.com/11ty/eleventy/issues/1435 is related.

Edit: looks like you can get around this by declaring component's require inside layout's render function:

function render(data) {
  let component = require('../components/component.11ty').render(data);
  return String.raw`
    ${component}
  `;
}

module.exports = {
  render,
};

JoshBeveridge avatar Apr 17 '23 03:04 JoshBeveridge

@substrae can you test the latest on GitHub? I’m guessing #2903 is the culprit

zachleat avatar Apr 17 '23 13:04 zachleat

@zachleat

You betcha! I'll take a peek after work today. 🚀

JoshBeveridge avatar Apr 17 '23 14:04 JoshBeveridge

@zachleat Hmm, installing fresh from master results in the same problem I described above. I created a mock project with the exact same basic folder structure and imports, and saving component triggers a build, but the change isn't reflected in the browser despite the page refresh.

Edit: for reference, the compiled HTML doesn't contain the change either.

Edit 2: my temporary solution from above also still works here, where moving the require into the render function solves the problem.

JoshBeveridge avatar Apr 17 '23 23:04 JoshBeveridge

@substrae: Thank you for this! 🤗 I am messing around with Preact and TypeScript for templating and couldn't figure out what was going on. This is what I have and I'm happy with it:

// base.11ty.tsx

import { h, Fragment } from "preact";
import { render as r } from "preact-render-to-string";

import type { EleventyData } from "../types/eleventy";
import { Shell } from "../components";

export function render(data: EleventyData) {
  const { Post } = require("./post");
  const { Photo } = require("./photo");

  return r(
    <Shell data={data}>
      {data.category === "photos" ? (
        <Photo data={data} />
        ) : (
        <Post data={data} />
      )}
    </Shell>
  );
}

And here's the Post component as an example:

// post.tsx

import { h } from "preact";
import { parse } from "preact-parser";

import { PostData } from "../types/data";
import { postDate } from "../helpers";
import { Tags } from "../components";

export const Post = ({ data }: { data: PostData }) => (
  <article>
    <header>
      <h1>
        <a href={data.url}>{data.title}</a>
      </h1>
    </header>
   {parse(data.content)}
    <footer>    
      <Tags tags={data.tags} />
      <time>{postDate(data.date, "dd MMMM yy")}</time>
    </footer>
  </article>
);

afreeorange avatar Sep 22 '23 21:09 afreeorange

Same issue with Preact and Typescript. Have to dynamic import/ require in the renderer for it to rebuild, when the imported components change.

briansunter avatar Oct 23 '23 23:10 briansunter

same issue again

avinashkanaujiya avatar Nov 12 '23 11:11 avinashkanaujiya

Still having this issue as well, and unfortunately I've run into a context where I can't move the require into the render() due to needing it in the data variable declaration. 😢

// Page data =======================================================================================

let data = {
  pagination: {
    data: 'guide_data',
    size: 1,
  },
  guide_data: require('../_data/guides').heavensward, // This is causing the problem
  permalink: function (data) {
    return data.pagination.items[0].slug;
  },
};

// Script ==========================================================================================

function render(data) {
  // Local component imports
  const guide_layout = require('../_layouts/guide.11ty');
  // Return the layout render
  return guide_layout.render(data, data.pagination.items[0]);
}

module.exports = {
  data,
  render,
};

JoshBeveridge avatar Mar 11 '24 18:03 JoshBeveridge