Giter VIP home page Giter VIP logo

Comments (17)

josevalim avatar josevalim commented on June 20, 2024 2

@jeregrine I don't want to add more stuff for us to debug, another server to run, etc.

from phoenix_live_reload.

chrismccord avatar chrismccord commented on June 20, 2024

Since you are using HMR, can you simply remove the js pattern from your live reload config? Or do you still require full phoenix_live_reload page refresh for js changes. I would prefer to wait on this change since it's the first time this has come up and I would like to avoid hitting disk if possible.

from phoenix_live_reload.

skinandbones avatar skinandbones commented on June 20, 2024

Hi @chrismccord 👋 Thanks for the awesome work!

This can wait – it's not blocking me at all. I've gotten everything working the way I like by using webpack-dev-server, HMR, and css-hot-loader. It's a non-trivial setup to say the least and took some integration work in the phoenix app for :dev vs. :prod. Not as clean as the brunch setup.

My initial goal was to use webpack in the simplest configuration (no HMR) and rely on phoenix_live_reload (a build agnostic tool). Once I figured out what was going on with the false positive JS asset changes, I realized I would have to get the webpack-dev-server involved .... and all the complexity that goes with it.

If not for this issue, I honestly think we could write a phoenix + webpack integration guide (or even a generator) that wouldn't blow up complexity. Things could pretty much work as they do in the default generated app. I know a lot of people coming to Phoenix would be interested in that.

I agree, this will touch the filesystem and it would have to keep state.

from phoenix_live_reload.

skinandbones avatar skinandbones commented on June 20, 2024

Since you are using HMR, can you simply remove the js pattern from your live reload config? Or do you still require full phoenix_live_reload page refresh for js changes.

With HMR (w/ webpack-dev-server), phoenix_live_reload will handle the refresh when the views and templates change. phoenix_live_reload isn't needed for refresh on js changes. In fact, the static assets generated by webpack don't even get written into the output directory so there are no file changes for phoenix_live_reload to detect.

from phoenix_live_reload.

jameskerr avatar jameskerr commented on June 20, 2024

I just ran into this as well. I loved brunch but it looks like it's not being maintained to the level I'm comfortable with. I switched from brunch to webpack.

My webpack setup outputs two files (js/index.js, css/app.css) each time css or js changes. This causes the whole page to refresh when I just change a style.

It's a non-trivial setup to say the least and took some integration work in the phoenix app for :dev vs. :prod. Not as clean as the brunch setup.

@skinandbones, like you, I'm hesitant to dive into the complexity of HMR with the webpack-dev-server. I'd much rather use standard live reload. Are there any new solutions now? A year later?

from phoenix_live_reload.

josevalim avatar josevalim commented on June 20, 2024

@jameskerr did you take a look at how Phoenix master handles webpack? Phoenix v1.4 will ship with webpack, so maybe this issue is fixed there (or maybe now all applications will have this issue).

from phoenix_live_reload.

josevalim avatar josevalim commented on June 20, 2024

Actually, it seems Phoenix master has this issue.

@chrismccord should we move this to the Phoenix repo so we can track it for the release?

from phoenix_live_reload.

jameskerr avatar jameskerr commented on June 20, 2024

Thanks for the quick response @josevalim . I just took a look at Phoenix master and found code very similar to what I just setup today. That's encouraging. I'll be tracking this. Please point me in any direction I might be able to help.

from phoenix_live_reload.

josevalim avatar josevalim commented on June 20, 2024

@jameskerr if you want to give this a try, it would be awesome. I think caching the MD5s on the Phoenix channel as proposed by @skinandbones is a good starting point.

from phoenix_live_reload.

jameskerr avatar jameskerr commented on June 20, 2024

I'll take look!

from phoenix_live_reload.

chrismccord avatar chrismccord commented on June 20, 2024

caching at the channel side won't be enough because the page refreshes and discards all channel state before starting a new channel. We can however have a separate process that boots with the app which watches for changes and the channel subscribes to it.

from phoenix_live_reload.

jeregrine avatar jeregrine commented on June 20, 2024

Should/Could we ship webpack with HMR/CSS loading using webpack's tools and reserve the phoenix loader for template/view changes?

from phoenix_live_reload.

skinandbones avatar skinandbones commented on June 20, 2024

@jeregrine Agree with @josevalim. I would not recommend using webpack for CSS hot reloading by default. I've been using a webpack HMR setup in my Phoenix apps since I submitted this issue, but it's not for everyone. The setup ripples into many things and stuff gets weird if you don't understand what's going on.

from phoenix_live_reload.

nkezhaya avatar nkezhaya commented on June 20, 2024

Super old thread, but just wanted to show how this could be done with esbuild. This is assets/build.js:

const fs = require("fs-extra")
const glob = require("glob")
const crypto = require("crypto")
const esbuild = require("esbuild")
const postCssPlugin = require("esbuild-plugin-postcss2")

const mode = process.env.NODE_ENV === "production" ? "production" : "development"
const devMode = mode === "development"

const sourcemap = devMode ? "external" : false
const minify = !devMode
const commonOptions = { sourcemap, minify, write: false }

// Keep track of file hashes so we only write the ones that changed
const getDigest = string => {
  const hash = crypto.createHash("sha1")
  const data = hash.update(string, "utf-8")
  const digest = data.digest("hex")

  return digest
}

const getFileDigest = path => {
  const exists = fs.pathExistsSync(path)

  if (!exists) {
    return null
  }

  if (fs.statSync(path).isDirectory()) {
    return null
  }

  return getDigest(fs.readFileSync(path))
}

const writeResult = result => {
  for (let { path, contents } of result.outputFiles) {
    const digest = getDigest(contents)

    if (getFileDigest(path) !== digest) {
      fs.outputFile(path, contents)
    }
  }

  return result
}

// Main app

esbuild.build({
  entryPoints: ["js/App.js"],
  bundle: true,
  target: "es2016",
  outfile: "../priv/static/js/app.js",
  ...commonOptions
}).then(writeResult)

esbuild.build({
  entryPoints: ["css/app.css"],
  bundle: true,
  outfile: "../priv/static/css/app.css",
  external: ["*.woff", "*.gif"],
  plugins: [postCssPlugin.default({
    plugins: [
      require("postcss-preset-env"),
      require("postcss-import"),
      require("tailwindcss"),
      require("postcss-mixins"),
      require("postcss-nested")
    ]
  })],
  ...commonOptions
}).then(writeResult)

// Copy assets/static to priv/static

function filter(src, dest) {
  const exists = fs.pathExistsSync(dest)

  if (!exists) {
    return true
  }

  if (fs.statSync(dest).isDirectory()) {
    return true
  }

  return getFileDigest(src) !== getFileDigest(dest)
}

fs.copySync("./static", "../priv/static", { filter })

from phoenix_live_reload.

nickjj avatar nickjj commented on June 20, 2024

It would be very useful if this was included by default. I'm also using esbuild with a much more simplified copy file approach. Changing 1 line of JS results in every static file being live reloaded when their contents didn't change.

You end up with this type of log output when editing any JavaScript:

js_1        | [watch] build finished
web_1       | [debug] Live reload: priv/static/android-chrome-512x512.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/apple-touch-icon.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/images/phoenix.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/mstile-150x150.png
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg
web_1       | [debug] Live reload: priv/static/safari-pinned-tab.svg

As a workaround whitepaperclip's solution works with Node 16.x. You could also avoid the 3rd party fs-extra Node dependency and replace fs.pathExistsSync with fs.existsSync to use Node's standard library.

If esbuild is being pushed as the Phoenix default it would be quite nice to have this behavior handled at the Phoenix Live Reload level, especially if you're pushing a message of not needing Node. You need Node to use a custom esbuild config.

from phoenix_live_reload.

nkezhaya avatar nkezhaya commented on June 20, 2024

fs.pathExistsSync still works, but note the const fs = require("fs-extra"); at the top.

from phoenix_live_reload.

nickjj avatar nickjj commented on June 20, 2024

fs.pathExistsSync still works, but note the const fs = require("fs-extra"); at the top.

Ah good catch. fs.existsSync works with Node's standard library. fs-extra looks to be a 3rd party package.

from phoenix_live_reload.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.