11ty / eleventy-dev-server

A minimal generic web-development web server.
101 stars 15 forks source link

Generated CSS and JS files do not trigger reload (using `input` or `addWatchTarget)` #42

Closed jeromecoupe closed 1 year ago

jeromecoupe commented 1 year ago

Version of Eleventy / Eleventy dev server

Steps to reproduce

  1. Configure Eleventy to output files in ./dist
  2. Generate CSS and JS files from ./src/assets/ to ./dist/assets/ output folder using NPM scripts (Sass and esbuild)
  3. Configure Eleventy Dev Server to pick up changes in output directory using input
module.exports = function (eleventyConfig) {
  // server options
  eleventyConfig.setServerOptions({
    port: 3000,
    input: "./dist",
  });

  // override base config
  return {
    dir: {
      input: "src",
      output: "./dist",
      markdownTemplateEngine: "njk",
    },
  };
};

Configuration seems to be working fine: the port changes to 3000

addWatchTarget does not work either

Tried adding addWatchTarget for source scss and js files. Not working for me either.

module.exports = function (eleventyConfig) {
  // watch targets to trigger a build
  eleventyConfig.addWatchTarget("./src/assets/scss/");
  eleventyConfig.addWatchTarget("./src/assets/js/");

  // server options
  eleventyConfig.setServerOptions({
    port: 3000,
    input: "./dist",
  });

  // override base config
  return {
    dir: {
      input: "./src",
      output: "./dist",
      markdownTemplateEngine: "njk",
    },
  };
};

If I comment out the server config and use eleventy 1.0.2, everythig works as expected, both watch targets trigger a build and a page reload.

Test repository

Here is a repository with a reduced test case if that helps.

Expected behaviour

Eleventy dev server reloads the project when any file changes in ./dist, be it generated by Eleventy or not. I am expecting this to be equivalent to browser-sync start --server \"./dist\" --files \"./dist\"

Actual behaviour

HTML files trigger a reload, while CSS and JS files do not.

jeromecoupe commented 1 year ago

Related: #19

jeromecoupe commented 1 year ago

Getting somewhere here. Thanks to Zach's help over on Mastodon, this looks like it is working as expected now. Seems I had a couple of problems / misunderstandings.

  1. Builds are now triggered. Deleted .eleventyignore and moving the ignore entries to API as per the changes in issue #893 over at @11ty/eleventy
  2. The other problem was that the builds seem to be faster than my asset pipelines (NPM Scripts + esbuild for JS and Sass for CSS). Adding eleventyConfig.setWatchThrottleWaitTime(200); seems to do the trick. Can see my CSS and JS changes now.

Full working config file

module.exports = function (eleventyConfig) {
  // ignore folders (those are not automatically ignored by the watcher anymore)
  eleventyConfig.ignores.add("./src/assets/");

  // watch targets (add small wait time before rebuild, tweak accordingly)
  eleventyConfig.setWatchThrottleWaitTime(200);
  eleventyConfig.addWatchTarget("./src/assets/scss/");
  eleventyConfig.addWatchTarget("./src/assets/js/");

  // server options
  eleventyConfig.setServerOptions({
    port: 3000,
  });

  // override base config
  return {
    dir: {
      input: "./src",
      output: "./dist",
      markdownTemplateEngine: "njk",
    },
  };
};

Relevant debug output (serve)

Eleventy Watching for changes to: [ './src/assets/scss/**/*', './src/assets/js/**/*', './src/**/*.liquid', './src/**/*.ejs', './src/**/*.md', './src/**/*.hbs', './src/**/*.mustache', './src/**/*.haml', './src/**/*.pug', './src/**/*.njk', './src/**/*.html', './src/**/*.11ty.js', './src/**/*.11ty.cjs', './src/_includes/**', './src/_data/**', './.eleventy.js', './eleventy.config.js', './eleventy.config.cjs', './src/**/*.json', './src/**/*.11tydata.cjs', './src/**/*.11tydata.js' ] +3ms
Eleventy Ignoring watcher changes to: [ 'node_modules/**', 'dist/**', './**/node_modules/**', './.git/**' ] +0ms

Full debug output (serve)

Eleventy:cmd command: eleventy { _: [], quiet: null, version: false, watch: false, dryrun: false, help: false, serve: true, passthroughall: false, incremental: false } +0ms
Eleventy:EventBus Setting up global EventBus. +0ms
Eleventy:UserConfig Resetting EleventyConfig to initial values. +0ms
Eleventy:UserConfig Adding universal filter 'slug' +5ms
Eleventy:UserConfig Adding universal filter 'slugify' +1ms
Eleventy:UserConfig Adding universal filter 'url' +0ms
Eleventy:UserConfig Adding universal filter 'log' +0ms
Eleventy:UserConfig Adding universal filter 'serverlessUrl' +0ms
Eleventy:UserConfig Adding universal filter 'getCollectionItem' +0ms
Eleventy:UserConfig Adding universal filter 'getPreviousCollectionItem' +0ms
Eleventy:UserConfig Adding universal filter 'getNextCollectionItem' +0ms
Eleventy:TemplateConfig rootConfig { templateFormats: [ 'liquid',   'ejs', 'md',       'hbs', 'mustache', 'haml', 'pug',      'njk', 'html',     '11ty.js' ], pathPrefix: '/', markdownTemplateEngine: 'liquid', htmlTemplateEngine: 'liquid', dataTemplateEngine: false, htmlOutputSuffix: '-o', jsDataFileSuffix: '.11tydata', keys: { package: 'pkg', layout: 'layout', permalink: 'permalink', permalinkRoot: 'permalinkBypassOutputDir', engineOverride: 'templateEngineOverride', computed: 'eleventyComputed' }, dir: { input: '.', includes: '_includes', data: '_data', output: '_site' }, handlebarsHelpers: {}, nunjucksFilters: {} } +0ms
Eleventy:TemplateConfig Setting pathPrefix to '/' +1ms
Eleventy Setting process.env.ELEVENTY_ROOT: '/Users/jeromecoupe/data/sandboxes/test-11ty-dev-server' +0ms
Eleventy:TemplateConfig Merging config with .eleventy.js +1ms
Eleventy:TemplateConfig overrides: { pathPrefix: '/' } +2ms
Eleventy:TemplateConfig Current configuration: { pathPrefix: '/', markdownTemplateEngine: 'liquid', htmlTemplateEngine: 'liquid', dataTemplateEngine: false, htmlOutputSuffix: '-o', jsDataFileSuffix: '.11tydata', keys: { package: 'pkg', layout: 'layout', permalink: 'permalink', permalinkRoot: 'permalinkBypassOutputDir', engineOverride: 'templateEngineOverride', computed: 'eleventyComputed' }, dir: { input: './src', includes: '_includes', data: '_data', output: './dist', markdownTemplateEngine: 'njk' }, handlebarsHelpers: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)] }, nunjucksFilters: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)] }, templateFormats: [ 'liquid',   'ejs', 'md',       'hbs', 'mustache', 'haml', 'pug',      'njk', 'html',     '11ty.js' ], transforms: {}, linters: {}, globalData: {}, layoutAliases: {}, passthroughCopies: {}, liquidOptions: {}, liquidTags: {}, liquidFilters: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)] }, liquidShortcodes: {}, liquidPairedShortcodes: {}, nunjucksEnvironmentOptions: {}, nunjucksPrecompiledTemplates: {}, nunjucksAsyncFilters: {}, nunjucksTags: {}, nunjucksGlobals: {}, nunjucksAsyncShortcodes: {}, nunjucksShortcodes: {}, nunjucksAsyncPairedShortcodes: {}, nunjucksPairedShortcodes: {}, handlebarsShortcodes: {}, handlebarsPairedShortcodes: {}, javascriptFunctions: { slug: [Function (anonymous)], slugify: [Function (anonymous)], url: [Function (anonymous)], log: [Function (anonymous)], serverlessUrl: [Function (anonymous)], getCollectionItem: [Function (anonymous)], getPreviousCollectionItem: [Function (anonymous)], getNextCollectionItem: [Function (anonymous)] }, pugOptions: {}, ejsOptions: {}, markdownHighlighter: null, libraryOverrides: {}, dynamicPermalinks: true, useGitIgnore: true, ignores: Set(3) { '**/node_modules/**', '.git/**', './src/assets/' }, watchIgnores: Set(2) { '**/node_modules/**', '.git/**' }, dataDeepMerge: true, watchJavaScriptDependencies: true, additionalWatchTargets: [ './src/assets/scss/**/*', './src/assets/js/**/*' ], serverOptions: { port: 3000 }, chokidarConfig: {}, watchThrottleWaitTime: 200, frontMatterParsingOptions: undefined, dataExtensions: Map(0) {}, extensionMap: Set(0) {}, quietMode: false, events: AsyncEventEmitter { _events: [Object: null prototype] {}, _eventsCount: 0, _maxListeners: undefined, [Symbol(kCapture)]: false }, benchmarkManager: BenchmarkManager { benchmarkGroups: { Configuration: [BenchmarkGroup], Aggregate: [BenchmarkGroup] }, isVerbose: true, start: 228.8373749256134 }, plugins: [], useTemplateCache: true, precompiledCollections: {}, dataFilterSelectors: Set(0) {}, libraryAmendments: {}, serverPassthroughCopyBehavior: 'passthrough', urlTransforms: [] } +0ms
Eleventy Eleventy warm up time (in ms) 241.71745800971985 +5ms
Eleventy:TemplatePassthroughManager Resetting counts to 0 +0ms
Eleventy:EleventyFiles .gitignore ignoring: ./node_modules/** +0ms
Eleventy:EleventyFiles .gitignore ignoring: ./dist/** +0ms
Eleventy Directories:
Eleventy Input (Dir): ./src
Eleventy Input (File): undefined
Eleventy Data: src/_data
Eleventy Includes: src/_includes
Eleventy Layouts: undefined
Eleventy Output: ./dist
Eleventy Template Formats: liquid,ejs,md,hbs,mustache,haml,pug,njk,html,11ty.js
Eleventy Verbose Output: false +2ms
Eleventy:EleventyFiles Searching for: [ './src/**/*.liquid', './src/**/*.ejs', './src/**/*.md', './src/**/*.hbs', './src/**/*.mustache', './src/**/*.haml', './src/**/*.pug', './src/**/*.njk', './src/**/*.html', './src/**/*.11ty.js', './src/**/*.11ty.cjs' ] +12ms
Eleventy:TemplateWriter Found: [ './src/content/pages/index.njk' ] +0ms
Eleventy:TemplatePassthroughManager TemplatePassthrough copy started. +18ms
Eleventy:TemplatePassthroughManager `addPassthroughCopy` config API paths: {} +0ms
Eleventy:TemplatePassthroughManager `addPassthroughCopy` config API normalized paths: [] +0ms
Eleventy:TemplateData Using '.11tydata' to find data files. +0ms
Eleventy:TemplateData getLocalDataPaths('./src/content/pages/index.njk'): [ './src/content/pages/index.11tydata.js', './src/content/pages/index.11tydata.cjs', './src/content/pages/index.11tydata.json', './src/content/pages/index.json', './src/content/pages/pages.11tydata.js', './src/content/pages/pages.11tydata.cjs', './src/content/pages/pages.11tydata.json', './src/content/pages/pages.json', './src/content/content.11tydata.js', './src/content/content.11tydata.cjs', './src/content/content.11tydata.json', './src/content/content.json', './src/src.11tydata.js', './src/src.11tydata.cjs', './src/src.11tydata.json', './src/src.json' ] +0ms
Eleventy:TemplateWriter ./src/content/pages/index.njk begun adding to map. +1ms
Eleventy:TemplatePassthroughManager TemplatePassthrough copy finished. Current count: 0 +2ms
Eleventy:Template Template date: using file’s 'birthtimeMs' for './src/content/pages/index.njk' of 2022-09-20T11:20:04.061Z (from 1663672804061.4211) +0ms
Eleventy:TemplateMap Caching collections objects. +0ms
Eleventy:Template Rendering permalink for './src/content/pages/index.njk': index.html becomes 'index.html' +1ms
Eleventy:TemplateMap Collection: collections.all size: 1 +1ms
Eleventy:TemplateMap Collection: collections.all size: 1 +0ms
Eleventy:TemplateWriter Template map created. +22ms
Eleventy:Logger Writing ./dist/index.html from ./src/content/pages/index.njk +0ms
Eleventy:Template ./dist/index.html written.. +5ms
Eleventy:Logger Benchmark      9ms  16%     2× (Aggregate) Searching the file system +1ms
Eleventy:Benchmark Benchmark      9ms  16%     2× (Aggregate) Searching the file system +0ms
Eleventy:Benchmark Benchmark      2ms   4%     1× (Aggregate) Template Compile +0ms
Eleventy:Benchmark Benchmark      2ms   4%     1× (Aggregate) > Compile > ./src/content/pages/index.njk +0ms
Eleventy:Benchmark Benchmark      1ms   2%     1× (Aggregate) Render +0ms
Eleventy:Benchmark Benchmark      1ms   2%     1× (Aggregate) > Render > ./src/content/pages/index.njk +0ms
[11ty] Wrote 1 file in 0.04 seconds (v2.0.0-canary.18)
Eleventy Finished writing templates. +41ms
Eleventy 
Eleventy       Getting frustrated? Have a suggestion/feature request/feedback?
Eleventy       I want to hear it! Open an issue: https://github.com/11ty/eleventy/issues/new +0ms
Eleventy Watching for changes to: [ './src/assets/scss/**/*', './src/assets/js/**/*', './src/**/*.liquid', './src/**/*.ejs', './src/**/*.md', './src/**/*.hbs', './src/**/*.mustache', './src/**/*.haml', './src/**/*.pug', './src/**/*.njk', './src/**/*.html', './src/**/*.11ty.js', './src/**/*.11ty.cjs', './src/_includes/**', './src/_data/**', './.eleventy.js', './eleventy.config.js', './eleventy.config.cjs', './src/**/*.json', './src/**/*.11tydata.cjs', './src/**/*.11tydata.js' ] +3ms
Eleventy Ignoring watcher changes to: [ 'node_modules/**', 'dist/**', './**/node_modules/**', './.git/**' ] +0ms
Eleventy:Benchmark Benchmark      5ms NaN%     1× (Watch) Start up --watch +5ms
Eleventy:Benchmark Benchmark      2ms NaN%     1× (Watch) Watching JavaScript Dependencies (disable with `eleventyConfig.setWatchJavaScriptDependencies(false)`) +0ms
[11ty] Watching…
Eleventy:TemplatePassthroughManager `addPassthroughCopy` config API paths: {} +27ms
Eleventy:TemplatePassthroughManager `addPassthroughCopy` config API normalized paths: [] +0ms
Eleventy Ignoring watcher changes to: [ 'node_modules/**', 'dist/**', './**/node_modules/**', './.git/**' ] +2ms
Eleventy:Logger Server at http://localhost:3000/ +27ms
pdehaan commented 1 year ago

Interesting… I wonder if we have an issue for the NaN% logging issue.

Eleventy:Benchmark Benchmark      5ms NaN%     1× (Watch) Start up --watch +5ms
Eleventy:Benchmark Benchmark      2ms NaN%     1× (Watch) Watching JavaScript Dependencies (disable with `eleventyConfig.setWatchJavaScriptDependencies(false)`) +0ms
zachleat commented 1 year ago

@jeromecoupe is this one okay to close or are there additional changes that need to be made?

I think I’d need to understand how the parallel asset pipelines are being used in your templates before I could answer additional questions about the throttling. Specifically, if they’re building assets directly to your output folder (e.g. _site), I would expect that to work—assuming you’re referencing those as HTTP requests (<script src>) and not trying to use them as includes inside of Eleventy templates.

jeromecoupe commented 1 year ago

@zachleat Thank you for looking into this. This is still baffling me to be honest. Maybe there is something I dont understand but bear with me.

Context: JS and CSS assets are generated independently from Eleventy (via NPM scripts) directly in my dist folder. They are not used in includes but referenced in my pages as a <link> tag in the head for CSS and as a <script> tag with deferattribute.

Expected (ideal) behaviour from the eleventy dev server: being able to watch the whole dist folder or subfolders and files and when something, anything changes, reload (probably with a debounce to avoid multiple reloads). This is a similar implementation to BrowserSync --files option.

Currently I only managed to make it work in two ways

  1. Watch targets and trigger a rebuild. Ignore gitignore entries, add two watch targets, one for CSS, one for JS on the source folders. I have to add setWatchThrottleWaitTime because without it Eleventy finishes to build before my assets are compiled folder (race condition). I also have to trigger an Eleventy build every time which seems wasteful to me.
  2. Build assets either to a folder (./temp/. Setup addPassthroughCopy to copy those files from the temp folder to the dist folder. No wasteful Eleventy rebuilds, server reloads but now my compiled assets are written twice to disc (to tmp via the NPM scripts and then by Eleventy from that temp folder to dist).

My preferred solution would be to be able to watch specific directories in dist to reload the Eleventy Dev Server when files are changed.

A Repository with a bare bones test is available.

zachleat commented 1 year ago

Yeah, I took a fresh look at this via #19 and I see what you mean. I think I’m considering this a duplicate of #19 for now and posted a hopefully-useful new comment over there: https://github.com/11ty/eleventy-dev-server/issues/19#issuecomment-1379221593