vuejs-templates / pwa

PWA template for vue-cli based on the webpack template
MIT License
3.04k stars 508 forks source link

"Uncaught SyntaxError: Unexpected token <" when refreshing page #165

Open MikaelEdebro opened 6 years ago

MikaelEdebro commented 6 years ago

Whenever I do a normal refresh, i get these error messages:

manifest.48cbf0211cc2b417df60.js:1    Uncaught SyntaxError: Unexpected token <
vendor.e73f0cf5e42d1a1bdeee.js:1    Uncaught SyntaxError: Unexpected token <
app.d644989e00d1de883ada.js:1    Uncaught SyntaxError: Unexpected token <

When looking in the Network tab, it´s like the entire HTML document (index.html) is being returned instead of the js file. https://imgur.com/a/6AR5P

I'm assuming this has to do with the src to the js-files are returning 404. Question is why though?

If I hit hard refresh (Ctrl + F5), the site loads fine.

Does anyone have any clues?

MikaelEdebro commented 6 years ago

Ok I think I have narrowed it down to the service-worker. If I check Application > Service Workers > Bypass for network, the site works again after soft refresh.

Any ideas?

MikaelEdebro commented 6 years ago

If I npm run build, and host it on localhost with serve, the service worker doesn't cause any issues.

For localhost, it says "from Service Worker" in the Size column (in Network tab). For UAT environment (where the issue appears), it says "from Disk Cache" https://imgur.com/a/puDOr

maxmilton commented 6 years ago

Does this happen in production builds? Pretty sure this is somehow related to webpack-dev-server's hot reload client script and so not something that should be of any concern.

MikaelEdebro commented 6 years ago

@MaxMilton Yes this is in prod builds. Just a question. The service-worker is supposed to cache index html right? And I assume that it picks up on CommonChunksPlugins hash changes?

Cause what I think I'm experiencing is that index.html is cached, but after a new deploy, the bundles in the cached index.html are no longer there (due to changes in file name hash).

However I might add that this is a bit of a modified setup. We're building a multi-tenant app, so we're creating an index.html for each tenant (and later in our build pipeline rename for example /dist/templates/UAT-AWS/index.TenantName.html --> /dist/index.html). Does it affect the "cache busting" of the SW if index.html is not really existing on disk? I mean, will the precache plugin not update the cacheId/hash if index.html is not created?

I'll just post our webpack.prod.config.js:

'use strict'

const fs = require('fs')
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const loadMinified = require('./load-minified')

const env = config.build.env

const webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    new CleanWebpackPlugin(['dist'], { root: path.join(__dirname, '..') }),
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        safe: true
      }
    }),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function(module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    // copy custom assets
    new CopyWebpackPlugin([
      { from: path.resolve(__dirname, '../static/tracking'), to: '' },
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      },
      { from: path.resolve(__dirname, '../Dockerfile'), to: '' },
      { from: path.resolve(__dirname, '../.dockerignore'), to: '' },
      { from: path.resolve(__dirname, '../../docker/configure-fe-runtime.sh'), to: '' }
    ]),
    // service worker caching
    new SWPrecacheWebpackPlugin({
      cacheId: 'booksecure-service-worker',
      filename: 'service-worker.js',
      staticFileGlobs: ['dist/**/*.{js,html,css}'],
      minify: true,
      stripPrefix: 'dist/'
    })
  ]
})

for (let environment of config.build.environments) {
  for (let tenant of config.build.tenants) {
    let runtimeConfig = require(`../config/runtime/${environment}/runtime-config.${tenant}.js`)
    webpackConfig.plugins.push(
      // generate dist index.html with correct asset hash for caching.
      // you can customize output by editing /index.html
      // see https://github.com/ampedandwired/html-webpack-plugin
      new HtmlWebpackPlugin({
        filename: `${config.build.assetsRoot}/templates/${environment}/index.${tenant}.html`, // yes, no .html extension to not let these files be served.
        template: 'index.html',
        inject: true,
        tenant: tenant,
        runtimeConfig: `
        <script id="runtimeConfig" type="text/javascript">
          window.runtimeConfig = {
            apiHost: '${runtimeConfig.API_HOSTNAME}',
            apiKey: '${runtimeConfig.API_KEY}'
          }
        </script>`,
        minify: {
          removeComments: true,
          collapseWhitespace: true,
          removeAttributeQuotes: true
          // more options:
          // https://github.com/kangax/html-minifier#options-quick-reference
        },
        // necessary to consistently work with multiple chunks via CommonsChunkPlugin
        chunksSortMode: 'dependency',
        serviceWorkerLoader: `<script>${loadMinified(
          path.join(__dirname, './service-worker-prod.js')
        )}</script>`
      })
    )
  }
}

if (config.build.productionGzip) {
  const CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp('\\.(' + config.build.productionGzipExtensions.join('|') + ')$'),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
MikaelEdebro commented 6 years ago

Okey guys! I've just verified that this is not actually a bug in the PWA template, but instead was related to the changes that we had made.

Since we were not creating a dist/index.html, the sw-precache-webpack-plugin could not pick up on changes, so it's "cache id" was the same. In service-worker.js:

var precacheConfig = [
    ['index.html', '91b2a317a09b223bf5a5582a5930069c'],
    ['static/css/app.3136db4aece9d70bd7458ade08e813c8.css', 'e685314d1221643e09338010621d36b5'],
    ['static/js/app.5a5b57a7c4b45cfcb1d8.js', '6045c0a02a2c055cefdb6d9d9e4574c7'],
    ['static/js/manifest.f52ceabe5f48b3ce1af2.js', 'fc67123c2142aea9e2dccf03ba3dbc5b'],
    ['static/js/vendor.85a0bf6fdf1309909410.js', 'e8f4ecbec293643c5f4b7b93744a4264']
  ],

Once we added back the creation of index.html, the hash/id updated correctly.

maxmilton commented 6 years ago

Glad to hear you found the culprit. It was a bit strange since I've not experienced it in any production builds before and I've worked on a lot of projects based on this template. Thanks for posting your solution too!

dev-meta commented 6 years ago

i met the same problem ,i want to know how did you handle this ,counld u please explain it in detail?

dev-meta commented 6 years ago

what did you do to let the hash/id update correctly? you said 'Once we added back the creation of index.html, the hash/id updated correctly.'

i don't understand exactly

waiting your reply thank you very much

nathanchikku commented 6 years ago

app.use(express.static(path.join(__dirname, 'dist/')));

nathanchikku commented 6 years ago

app.use(express.static(path.join(__dirname, 'dist/todos')));

after dist you should write the project name

jainshravan123 commented 6 years ago

See this guys https://github.com/webpack/webpack/issues/2882#issuecomment-280906981

You just need to add <base href="/" /> into the <head> of your index.html. This resolved my problem. It may help you too.

Thanks

jainshravan123 commented 6 years ago

@MikaelEdebro Can you please review and close this issue.

akerdi commented 5 years ago

Uncaught SyntaxError: Unexpected token < means server already send index.html file to chrome, but server can't find your frontend static path.

app.use(express.static(path.join(__dirname, 'public/'))))

server use static path, solve problem.

Dinduks commented 4 years ago

I get the same issue but not on every refresh, only sometimes after I deploy the app.

From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <).

A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones.

Has anyone been in the same situation?

davidjnorth commented 4 years ago

@Dinduks did you find a solution to your problem? I'm having a similar issue where I get the error sometimes after deploys.

KaleRakker commented 4 years ago

I am having issues with this too. On every page refresh, the page gives this error. After a hard page refresh (ctrl + F5), it is fixed. Does someone know how to fix this?

pdemilly commented 4 years ago

I am getting the same error when I deploy a new version and but a user already logged in my SPA loads a module dynamically in the previous version. I guess I would need to trap those errors and force a reload

Dinduks commented 4 years ago

Hey @davidjnorth, I just noticed your message.
No I haven't found a solution yet. I experimented a few hours with different Google results, in vain.

I was thinking I'll just go the @pdemilly route and find some way to detect this problem then force a refresh.

What did you guys do?

IrvinCode commented 4 years ago

Any idea to how to fix that? I am have a same issue

I will force refresh to fix the issue but this is a forced fix.

Any idea what is happening?

Sonequa commented 4 years ago

See this guys webpack/webpack#2882 (comment)

You just need to add <base href="/" /> into the <head> of my index.html. This resolved my problem. It may help you too.

Thanks

Man this has saved my life. For my situation, I deploy my react client on express as the documentation of create-react-app said. Everything works fine, except when I refreshing a page whose URL contains a param. I've searched for a whole day. This is the only way which solved my problem perfectly for now. Hope it will help you guys, too.

Dinduks commented 4 years ago

@Sonequa Thanks! Unfortunately that didn't work for me. I wonder if it's related to the fact that the error doesn't happen after every update for every users.

paolog22 commented 4 years ago

same issue here. already did this

You just need to add into the of my index.html.

zawadsoon commented 4 years ago

I get the same issue but not on every refresh, only sometimes after I deploy the app.

From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <).

A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones.

Has anyone been in the same situation?

@Dinduks You probably caches the index.html without the js files.

So, when you build (deploy) app the js files changes (sometimes). But index.html is loaded from cache and has references to old js files.

Error occurs sometimes because hash in the js files that you mentioned changes only when dependencies in package.json changes.

kostaslamo commented 4 years ago

I get the same issue but not on every refresh, only sometimes after I deploy the app. From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <). A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones. Has anyone been in the same situation?

@Dinduks You probably caches the index.html without the js files.

So, when you build (deploy) app the js files changes (sometimes). But index.html is loaded from cache and has references to old js files.

Error occurs sometimes because hash in the js files that you mentioned changes only when dependencies in package.json changes.

A quick solution for this is to edit your index.html file. I have added an attribute which i name it version in the meta tag and change its value in each deploy. For e.x: <meta version="1.0.1">. That causes a new index.html to be used without using the previous indexed one and solves the Unexpected token error.

JPilson commented 4 years ago

Try adding <base href="/" /> into the <head> in your index.html This worked for me .

matneves commented 4 years ago

I get the same issue but not on every refresh, only sometimes after I deploy the app. From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <). A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones. Has anyone been in the same situation?

@Dinduks You probably caches the index.html without the js files. So, when you build (deploy) app the js files changes (sometimes). But index.html is loaded from cache and has references to old js files. Error occurs sometimes because hash in the js files that you mentioned changes only when dependencies in package.json changes.

A quick solution for this is to edit your index.html file. I have added an attribute which i name it version in the meta tag and change its value in each deploy. For e.x: <meta version="1.0.1">. That causes a new index.html to be used without using the previous indexed one and solves the Unexpected token error.

I did the same here. It's quick and solves the issue.

mainaak commented 3 years ago

Whenever I do a normal refresh, i get these error messages:

manifest.48cbf0211cc2b417df60.js:1    Uncaught SyntaxError: Unexpected token <
vendor.e73f0cf5e42d1a1bdeee.js:1    Uncaught SyntaxError: Unexpected token <
app.d644989e00d1de883ada.js:1    Uncaught SyntaxError: Unexpected token <

When looking in the Network tab, it´s like the entire HTML document (index.html) is being returned instead of the js file. https://imgur.com/a/6AR5P

I'm assuming this has to do with the src to the js-files are returning 404. Question is why though?

If I hit hard refresh (Ctrl + F5), the site loads fine.

Does anyone have any clues?

For us the issue was occurring because we had the build deployed on two instances. Sometimes the browser requested index.html from the Machine 1 and then asked the Machine 2 for styles and javascript which were different because of the difference in hashes when the build is built and minified.

SalmanUlla commented 3 years ago

@Dinduks

I get the same issue but not on every refresh, only sometimes after I deploy the app.

From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <).

A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones.

Has anyone been in the same situation?

Facing the same issue. Where you able to find a solution or a workaround for this ?

mainaak commented 3 years ago

@Dinduks

I get the same issue but not on every refresh, only sometimes after I deploy the app. From what I understand, the first time I open the app it tries to load a JS files from the previous version (e.g. chunk-9a00505e.02e15df7.js), which doesn't exist anymore, and which serves a 404 HTML page (that obviously starts with <). A refresh fixes this, except on progressive web apps on Safari because there is no reload button nor a "swipe down to refresh" action. It's very frustrating for users, as well as for me who asks them to restart their phones. Has anyone been in the same situation?

Facing the same issue. Where you able to find a solution or a workaround for this ?

Are you deploying your build on multiple instances?

mgdeveloper79 commented 3 years ago

I am posting this in a hope help others incase if they reach this far and still have not found a fix. So along with many other issues, one possibility is if you are using html-webpack-plugin, you may find my answer useful. https://github.com/webpack/webpack-dev-middleware/issues/205

danzyaka commented 1 year ago

У меня возникает та же проблема, но не при каждом обновлении, а только иногда после развертывания приложения. Насколько я понимаю, при первом открытии приложения оно пытается загрузить файлы JS из предыдущей версии (например chunk-9a00505e.02e15df7.js), которая больше не существует и которая обслуживает HTML-страницу 404 (которая, очевидно, начинается с <). Обновление исправляет это, за исключением прогрессивных веб-приложений в Safari, поскольку нет ни кнопки перезагрузки, ни действия «проведите вниз, чтобы обновить». Это очень расстраивает пользователей, а также меня, когда они просят перезагрузить свои телефоны. Кто-нибудь был в такой же ситуации?

@DinduksВероятно, вы кэшируете index.html без файлов js. Итак, когда вы создаете (развертываете) приложение, файлы js меняются (иногда). Но index.html загружается из кеша и содержит ссылки на старые js-файлы. Иногда возникает ошибка, потому что хэш в js-файлах, о которых вы упомянули, меняется только при изменении зависимостей в package.json.

Быстрое решение для этого — отредактировать index.htmlфайл. Я добавил атрибут, который я называю версией в метатеге, и меняю его значение при каждом развертывании. Например: <meta version="1.0.1">. Это приводит к тому, что новый index.html используется без использования предыдущего проиндексированного и устраняет непредвиденную ошибку токена.

Я сделал то же самое здесь. Это быстро и решает проблему.

Hi guys! I had the same problem and i solved it inserting "no-cache" headers to server responce index.html. I think the problem exist because browser has his own cache in addition to cacheStorage. Headers that i used:

Cache-control: cache-control: no-store, must-revalidate Expires: 0 Pragma: no-cache

I hope it will solve your problems