symfony / webpack-encore

A simple but powerful API for processing & compiling assets built around Webpack
https://symfony.com/doc/current/frontend.html
MIT License
2.23k stars 198 forks source link

versioned icons not found in the manifest.json in PWA configuration using .configureManifestPlugin #796

Open MarlonAEC opened 4 years ago

MarlonAEC commented 4 years ago

Hi I have active the .enableVersioning() option in my webpack.config.js file and I also configured the seed key/values for my PWA using .configureManifestPlugin like this:

var Encore = require('@symfony/webpack-encore');
var ManifestPlugin = require('webpack-manifest-plugin');
var OfflinePlugin = require('offline-plugin');
const CopyPlugin = require('copy-webpack-plugin');

if (!Encore.isRuntimeEnvironmentConfigured()) {
    Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}

Encore
    // directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // public path used by the web server to access the output path
    .setPublicPath('/build')
    // only needed for CDN's or sub-directory deploy
    //.setManifestKeyPrefix('build/')

    .addEntry('app', './assets/js/app.js')
    .addEntry('sw', './assets/js/serviceWorker.js')

    .splitEntryChunks()

    .disableSingleRuntimeChunk()

    .cleanupOutputBeforeBuild()
    .enableBuildNotifications()
    .enableSourceMaps(!Encore.isProduction())

//ENABLING VERSIONING HERE
    .enableVersioning(Encore.isProduction())

    .configureBabelPresetEnv((config) => {
        config.useBuiltIns = 'usage';
        config.corejs = 3;
    })
    .configureBabel(function(babelConfig){
        babelConfig.plugins.push("@babel/plugin-proposal-class-properties");
    })
    .enableSassLoader()

    .autoProvidejQuery()
    .enableReactPreset()

//COPYING THE HASHED ICONS TO THE PUBLIC FOLDER I REALLY DON'T KNOW IF THERE IS ANOTHER WAY TO DO THIS
    .copyFiles(
        {
            from: './assets/img/icons',
            to: 'images/icons/[path][name].[hash:8].[ext]',
            pattern: /\.(png|jpg|jpeg)$/
        }
    )
//ADDING PWD KEYS TO MANIFEST.JSON
    .configureManifestPlugin( (options) =>{
        options.seed = {
            "name": "bla bla bla",
            "short_name": "bla",
            "display": "standalone",
            "start_url": ".",
            "background_color": "#fff",
            "theme_color": "#1c97b0",
            "orientation": "portrait-primary",
            "icons": [
                {
                    "src": "/build/images/icons/icon-512x512.png", //IS THIS THE CORRECT URL???????
                    "type": "image/png",
                    "sizes": "512x512"
                },
                {
                    "src": "/build/images/icons/icon-192x192.png", //IS THIS THE CORRECT URL???????
                    "type": "image/png",
                    "sizes": "192x192"
                }
            ]
          }        
    })

    var config = Encore.getWebpackConfig();

    config.plugins.push(new OfflinePlugin({
        "strategy": "changed",
        "responseStrategy": "cache-first",
        "publicPath": "/build/",
        "caches": {
            "main": [
                '*.json',
                '*.css', 
                '*.js',
                'img/*'
            ]
        },
        "ServiceWorker": {
            "events": !Encore.isProduction(),
            "entry": "./assets/js/serviceWorker.js",
            "cacheName": "Reysis",
            "navigateFallbackURL": '/',
            "minify": !Encore.isProduction(),
            "output": "./../sw.js",
            "scope": "/"
        },
        "AppCache": null
    }));
;

module.exports = Encore.getWebpackConfig();

my final manifest.json is this

{
  "name": "bla bla bla",
  "short_name": "bla",
  "display": "standalone",
  "start_url": ".",
  "background_color": "#fff",
  "theme_color": "#1c97b0",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/build/images/icons/icon-512x512.png",
      "type": "image/png",
      "sizes": "512x512"
    },
    {
      "src": "/build/images/icons/icon-192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ],
  "build/app.css": "/build/app.css",
  "build/app.js": "/build/app.js",
  "build/sw.js": "/build/sw.js",
  "build/vendors~app.css": "/build/vendors~app.css",
  "build/vendors~app.js": "/build/vendors~app.js",
  "build/vendors~app~sw.js": "/build/vendors~app~sw.js",
  "build/images/icons/icon-192x192.png": "/build/images/icons/icon-192x192.3d157c59.png",
  "build/images/icons/icon-512x512.png": "/build/images/icons/icon-512x512.b6511709.png"
}

but I got a not found icon in the browser when trying to load icons from the manifest,... My question is: Is this the correct way to add my PWA settings to the manifest.json? or ... Is it necessary to add the hash to the icons inside the .configManifestPlugin in the seed option? I am a little new using Encore, maybe I am doing something wrong, sorry for the inconvenience and thanks in advance...

I'm using Reactjs for the Frontend

Kocal commented 4 years ago

Hi,

You are confusing the manifest.json from Webpack Manifest Plugin and the manifest.json for PWA. They don't have the same goals and can not be "merged" in a single manifest.json file.

As a workaround, you can configure the manifest.json filename used by Webpack:

Encore.
  .configureManifestPlugin(options => {
    options.fileName = 'webpack-manifest.json';
  })

If you are using Symfony with the Symfony Webpack Encore Bundle, you will have to configure framework.assets.json_manifest_path to target the new webpack-manifest.json file.


The URL you use in your manifest.json file is not correct, you should not use build/images/icons/icon-192x192.png but /build/images/icons/icon-192x192.3d157c59.png.

But the hash 3d157c59 is not predictable, so you can't use a raw value here.

You can disable the hash for images by using Encore.configureFilenames():

Encore
  .configureFilenames({
    images: 'images/[name].[ext]'
  })

I'm not a big fan, a better solution would be to generate your PWA's manifest.json after Webpack has built entries (or resolved entries names). This way you will be able to use something like this:

Encore.addPlugin(MyPlugin([
  {
    name: 'manifest.json',
    content(webpackEntries) {
      const json = {
        // ...
        'icons': [
          {
            'src': webpackEntries['build/images/icons/icon-512x512.png'], // should resolve to /build/images/icons/icon-512x512.b6511709.png
            'type': 'image/png',
            'sizes': '512x512',
          },
          {
            'src': webpackEntries['build/images/icons/icon-192x192.png'], // should resolve to /build/images/icons/icon-192x192.3d157c59.png
            'type': 'image/png',
            'sizes': '192x192',
          },
        ],
      };

      return JSON.stringify(json, null, 2);
    },
  },
]);

I don't think such a plugin exists, but you can create your own I guess.

MarlonAEC commented 4 years ago

@Kocal Thanks for the answer it help me a lot to understand the differences between the both manifest and I solve the first part of the problem.... the second part well... is there some place where I can read more about how to solve it?? also I was inspecting using the dev tools and I saw that in the Sources tab, the images folder is not there... but if I check the public path it is beeing copied to that location due the .copyFile() function in the webpack.config.js file... is this normal?? could this be part of the problem?? Cheers!!

Kocal commented 4 years ago

Ah! Sorry, I didn't see you used .copyFiles!

Then you can use instead:

Encore
    .copyFiles(
        {
            from: './assets/img/icons',
            to: 'images/icons/[path][name].[ext]',
            pattern: /\.(png|jpg|jpeg)$/
        }
    )
Rodrigo001-dev commented 4 years ago

Project made with TypeScript, react.Js, React-native. Recycling day design

https://github.com/Rodrigo001-de/Projeto-Ecoleta-advanced

FlorianLeMenn commented 2 years ago

Other solution to copy manifest.json PWA into build folder :

Encore
.addPlugin(new CopyWebpackPlugin({
        patterns: [
            { from: './assets/icon_pwa', to: 'icon_pwa' },
            { from: './assets/manifest.json', to: path.resolve(__dirname, 'public/build', 'manifest.json') }
        ],
    }))