Crud: [4.0][Feature][Proposal] Remove dependency on CDNs - make Backpack work offline

Created on 17 Jul 2019  Ā·  18Comments  Ā·  Source: Laravel-Backpack/CRUD

Bug report

It would be nice to go CDN independent. Right now backpack does not work without internet.
I did it on my project, by including/downloading the following files:

  • dataTables.bootstrap-1.10.16.min.css
  • dataTables.bootstrap-1.10.16.min.js
  • dataTables.fixedHeader-3.1.5.min.js
  • dataTables.responsive-2.2.1.min.js
  • fixedHeader.dataTables-3.1.5.min.css
  • jquery.dataTables-1.10.16.min.js
  • responsive.bootstrap-2.2.1.min.css
  • responsive.bootstrap-2.2.1.min.js

Almost everything is related to Data Tables.

I may contribute with this, do you think this is a nice to have feature?

MUST breaking change

Most helpful comment

Thanks @promatik - Solution 3 sounds like the best one right now, I agree. Thanks for prototyping the solution, glad to hear it works well.

Still not very happy that people have to install npm and stuff, but... hey ho. At some point, all Laravel developers will _need to_ learn npm and maybe webpack. Just like composer was uncomfortable, but a step in the right direction.

All 18 comments

Hi @promatik ,

Totally agree. I actually think it's a MUST, not a nice-to-have. It's noted in the task list for v4 alpha.

@alashow submitted PR https://github.com/Laravel-Backpack/CRUD/pull/1007 for it a long time ago (in 2017) but unfortunately I didn't see the light back then :-) I have to admit - he was right, I was wrong.

The importance of removing all usage of CDNs struck me a few months ago, when Datatables' CDN went down for _a few hours_. Most people had caching enabled so they weren't affected, but new users wouldn't have those files cached, so they couldn't use Backpack. That's the big downside with CDNs - you have to trust that they're up more than you are. If they're not, it defeats the whole purpose.

Solution 1)

Remove every reference to CDNs and place those files locally. Publish the files upon Backpack installation. Easy to do. But difficult to push updates to js afterwards (only with breaking changes).

Solution 2)

Since we now have control of the underlying theme (Backstrap, based on CoreUI instead of AdminLTE), another option would be to just compile some backpackPlugins.js and backpackPlugins.css bundles, and load those two files with all plugins, fields and columns needed for Backpack to work. I wonder how big it would get, though. And it would still be a breaking change to change something in JS or CSS, unless we load these two files from our own CDN. Which... what did we solve here? :-)

Solution 2)

Since we're going to work on how we load css & js assets, I think it's a good opportunity to also consider using Laravel Mix. But I don't know if there's a solution for Backpack to use Laravel Mix behind the scenes, _without_ the developer installing npm, webpack and running build commands. Cause it would be one more technology that we impose when using Backpack. And I don't like that. Plus, there's the question of how do you separate the mix configuration of your app, from the mix configuration of your admin panel. Two mix files maybe? I'm not sure you _can_ do that.

What do you think about the options above? What did you have in mind?

Cheers!

Hi @tabacitu! I'll leave here my opinion :)

Solution 1 was what I did in my own project, it's the quick way to solve this. For backpack it has a huge downside, pushing asset updates.
Solution 2 has the same problem, either any update would require publishing the new assets, or by using our own CDN backpack would not work offline.

I like Solution 3, I like Laravel Mix šŸ‘
Yes, it has the downside of requiring an extra step/technology to setup backpack, but everything would be more clean and any updates on asset files would be automatic.


Regarding your doubt about how to setup Laravel Mix, I just tested a solution that may fit our needs;

I placed a mix config file on backpack vendor \vendor\backpack\base\src\backpack.mix.js, with a sample Laravel mix configuration:

mix.styles([
    "vendor/backpack/base/src/public/base/backpack.content.is.king.css",
    "vendor/backpack/base/src/public/pnotify/pnotify.custom.min.css",
    ...
], 'public/css/backpack.css');

Then we just need to require that file in the main Laravel Mix file:

let mix = require('laravel-mix');
...

// Backpack
require('./vendor/backpack/base/src/backpack.mix.js');

By running npm run prod both files will run and compile assets.


Let's hear more opinions on this šŸ‘

Thanks @promatik - Solution 3 sounds like the best one right now, I agree. Thanks for prototyping the solution, glad to hear it works well.

Still not very happy that people have to install npm and stuff, but... hey ho. At some point, all Laravel developers will _need to_ learn npm and maybe webpack. Just like composer was uncomfortable, but a step in the right direction.

@OliverZiegler and I also hope for using Laravel Mix :-)

We also had trouble with datatables CDN in the last weeks. And there is always GDPR in our mind.

Yes - there are additional steps, but I think they are not too complicated and easy to learn. The pros outweigh the cons im my eyes.

Guys,

You can find the move to Laravel Mix for Backpack/Base here. Will follow-up with Backpack/CRUD PR when it's done.

Let me know what you think about the approach.

Cheers!

But I don't know if there's a solution for Backpack to use Laravel Mix behind the scenes, without the developer installing npm, webpack and running build commands.

Sorry if I'm misunderstanding... but isn't the solution that backpack should _include compiled assets_ (created by Mix), so the typical Backpack user _doesn't_ have to run Mix? Surely mix would only need running any time any of the assets it's processing (CSS/JS used by Backpack basically) change, and the 'average Backpack user' won't be editing any of the included CSS/JS?

This would mean that any time a Backpack contributor edits and CSS or JS they would have to run Mix before pushing their changes to GitHub... or you can presumably set up a CI service to do this for you (I think, this part is a bit new to me)

@johnpuddephatt we are still investigating how this can be achieved.

Main problem I see is if developers don't need to execute mix after a backpack update, how do they get the changes a contributor may have made.
We could still force developers to override assets in the public folder on composer updates and provide precompiled versions on each release?
But this will lead to issues with cache busting (same file names, changed content), missing entries in the mix-manifest .json (as we should load mix compiled files via mix helper) and probably some other stuff.

@OliverZiegler Thanks that gives me a clearer understanding of the issues.

Regarding the cache busting part... the mix() helper accepts a second parameter: mix($path, $manifestDirectory = '') which might help – it might mean Backpack could keep its own manifest (or manifests... one for Base, one for CRUD, etc.) separate from the main app?

@johnpuddephatt @OliverZiegler

That was my conclusion too. That was the best solution I could find for Backpack\Base, and I've implemented it in this PR - https://github.com/Laravel-Backpack/Base/pull/385 . It has no cachebusting, though, for that please see below.

As you guys said:

  • Backpack maintainers use Mix, developers don't have to
  • we publish the bundled assets
  • if maintainers change CSS/JS files, new bundled files need to get published and overwrite the old ones

To overwrite public assets after each composer update, we could ask developers to add this command in their composer.json. Or we add it upon Backpack/Base and Backpack/CRUD installation:

    "scripts": {
        "post-root-package-install": [
            "php -r \"copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall"
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
+           "@php artisan vendor:publish --provider='Backpack\Base\BaseServiceProvider' --tag='public' --force",
+           "@php artisan vendor:publish --provider='Backpack\CRUD\CrudServiceProvider' --tag='public' --force",
        ],
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover"
        ]
    },

--

Cachebusting Solution A - Using mix()

@johnpuddephatt , I did NOT know that mix() had a second argument, thank you! I just tried it and added it to this PR.

It sounded like a great solution, but I hit a few problems:

  • _only public paths can be given as a second parameter (to the manifest file); ok then, we can publish the mix-manifest.json file along with the CSS and JS bundle, I said;_
  • _but the Base manifest file will NOT have the correct paths to the _published_ items, it will have the paths to the css & js inside the vendor/backpack/base folder; so the mix() helper will not work with our mix-manifest.json file;_
  • _we could also replace all paths in the mix-manifest.json file, one by one, according to where we published them, so that they're pointed to the correct files; but... it seems like a hack - doesn't it?

Honestly, I'm not sure using the mix() helper for cache busting makes sense as a package developer. Sound like over-engineering: we generate a mix-manifest file, then publish it, then rewrite it, only for this mix file to help with one thing - a unique string for cachebusting.

I might have another solution.

Cachebusting Solution B - Using ?v=1.x

So if we _were_ to use the mix-manifest file as parameter, our array of css/js assets in config/backpack/base.php would have been:

    // JS files that are loaded in all pages, using Laravel's mix() helper
    'mix_scripts' => [
-         'packages/backpack/base/js/bundle.js',
+         'packages/backpack/base/js/bundle.js' => 'packages/backpack/base', // asset => manifest_path
    ],

But since the mix() helper only helps us deal with cachebusting... why don't we _manually_ add a version tag at the end of the file path?

    // JS files that are loaded in all pages, using Laravel's asset() helper
    'scripts' => [
-         'packages/backpack/base/js/bundle.js',
+         'packages/backpack/base/js/bundle.js?v='.\PackageVersions\Versions::getVersion('backpack/base')
    ],

This makes the array _look_ a bit hacky, but:

  • it's actually A LOT less hacky then using the mix() helper, for the Backpack maintainers;
  • it's easier to understand by the end-developers;
  • it's easy to use and customize by end-developers, including for their own assets;

What do you think?

I've updated this PR to use cache-busting solution B. If we keep B, should we maybe remove the mix_styles and mix_scripts arrays? Or maybe developers could still use them to load their own assets, bundled with Mix in the app, or other packages? Not really sure.

PS. This Laravel Mix solution works well for Backpack/Base, but I'm not sure this will also go well with Backpack/CRUD (having two big backpack.crud.bundle.js and backpack.crud.bundle.js files). I imagine including all JS plugins will make the bundle files HUGE. I'll try it after I finish all new Base features for v4.

I haven’t had time to look into it properly but agree that generate/publish/rewrite seems overkill. I wasn’t sure at first but according to this article https://www.impressivewebs.com/cache-busting-front-end-resources-file-name-revving-still-necessary/, query string cache busting works just fine, so that’s good!

Might be cleaner to keep the array without the query string, and append it when rendered? You already have the base version number in the boot method of BaseServiceProvider, so it could look something like this:

<link rel="stylesheet" type="text/css" href="{{ asset($path) }}?v={{ $_SERVER['BACKPACK_BASE_VERSION'] }}">

but I'm not sure this will also go well with Backpack/CRUD…

No CRUD is clearly trickier! I think it’s worth getting Base right and then moving on to thinking about that properly. A sensible first step might be to do some pruning/housekeeping… for instance if you switched to server side exports that loses quite a lot of JS.

It’s also tricker because of the amount of JS and CSS mixed in with PHP, I’m guessing from the empty create.js, crud.js, edit.js, etc. files there was a hope to address this but I realise it’s not a straightforward task. If all code was cleanly split out (including for fields, though this would require making each field a folder with a field.php, field.css and field.js file) then you’d be able to use mix with all the benefits of a proper build process… writing modern cleaner JS, handling asset loading, tree shaking and minification.

On 31 Jul 2019, at 09:29, Cristian Tabacitu notifications@github.com wrote:

@johnpuddephatt https://github.com/johnpuddephatt @OliverZiegler https://github.com/OliverZiegler
That was my conclusion too. That was the best solution I could find for Backpack\Base, and I've implemented it in this PR - Laravel-Backpack/Base#385 https://github.com/Laravel-Backpack/Base/pull/385 . It has no cachebusting, though, for that please see below.

As you guys said:

Backpack maintainers use Mix, developers don't have to
we publish the bundled assets
if maintainers change CSS/JS files, new bundled files need to get published and overwrite the old ones
To overwrite public assets after each composer update, we could ask developers to add this command in their composer.json. Or we add it upon Backpack/Base and Backpack/CRUD installation:

"scripts": {
    "post-root-package-install": [
        "php -r \"copy('.env.example', '.env');\""
    ],
    "post-create-project-cmd": [
        "php artisan key:generate"
    ],
    "post-install-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postInstall"
    ],
    "post-update-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postUpdate",

  • "@php artisan vendor:publish --provider='Backpack\Base\BaseServiceProvider' --tag='public' --force",
  • "@php artisan vendor:publish --provider='Backpack\CRUD\CrudServiceProvider' --tag='public' --force",
    ],
    "post-autoload-dump": [
    "Illuminate\Foundation\ComposerScripts::postAutoloadDump",
    "@php artisan package:discover"
    ]

},

Cachebusting Solution A - Using mix()

@johnpuddephatt https://github.com/johnpuddephatt , I did NOT know that mix() had a second argument, thank you! I just tried it and added it to this PR https://github.com/Laravel-Backpack/Base/pull/387.

It sounded like a great solution, but I hit a few problems:

only public paths can be given as a second parameter (to the manifest file); ok then, we can publish the mix-manifest.json file along with the CSS and JS bundle, I said;
but the Base manifest file will NOT have the correct paths to the published items, it will have the paths to the css & js inside the vendor/backpack/base folder; so the mix() helper will not work with our mix-manifest.json file;
_we could also replace all paths in the mix-manifest.json file, one by one, according to where we published them, so that they're pointed to the correct files; but... it seems like a hack - doesn't it?
Honestly, I'm not sure using the mix() helper for cache busting makes sense as a package developer. Sound like over-engineering: we generate a mix-manifest file, then publish it, then rewrite it, only for this mix file to help with one thing - a unique string for cachebusting.

I might have another solution.

Cachebusting Solution B - Using ?v=1.x

So if we were to use the mix-manifest file as parameter, our array of css/js assets in config/backpack/base.php https://github.com/Laravel-Backpack/Base/pull/387 would have been:

// JS files that are loaded in all pages, using Laravel's mix() helper
'mix_scripts' => [

- 'packages/backpack/base/js/bundle.js',
+ 'packages/backpack/base/js/bundle.js' => 'packages/backpack/base', // asset => manifest_path
],
But since the mix() helper only helps us deal with cachebusting... why don't we manually add a version tag at the end of the file path?

// JS files that are loaded in all pages, using Laravel's asset() helper
'scripts' => [

- 'packages/backpack/base/js/bundle.js',
+ 'packages/backpack/base/js/bundle.js?v='.\PackageVersions\Versions::getVersion('backpack/base')
],
This makes the array look a bit hacky, but:

it's actually A LOT less hacky then using the mix() helper, for the Backpack maintainers;
it's easier to understand by the end-developers;
it's easy to use and customize by end-developers, including for their own assets;
What do you think?

I've updated this PR https://github.com/Laravel-Backpack/Base/pull/387 to use cache-busting solution B. If we keep B, should we maybe remove the mix_styles and mix_scripts arrays? Or maybe developers could still use them to load their own assets, bundled with Mix in the app, or other packages? Not really sure.

PS. This Laravel Mix solution works well for Backpack/Base, but I'm not sure this will also go well with Backpack/CRUD (having two big backpack.crud.bundle.js and backpack.crud.bundle.js files). I imagine including all JS plugins will make the bundle files HUGE. I'll try it after I finish all new Base features for v4 https://github.com/Laravel-Backpack/Base/pull/384.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/Laravel-Backpack/CRUD/issues/1938?email_source=notifications&email_token=AB5IVPREH6LKXDOFVKRSC4TQCFEM5A5CNFSM4IESPEG2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3GQA6Y#issuecomment-516751483, or mute the thread https://github.com/notifications/unsubscribe-auth/AB5IVPTTMAGAT54NZWB2FRLQCFEM5ANCNFSM4IESPEGQ.

Need someone to check but I think lines like this:

@if (config('backpack.base.overlays') && count(config('backpack.base.overlays')))

can be simplified to:

@if(!empty(config('backpack.base.overlays')))

I tested having an empty array for backpack.base.overlays as well as having it missing and it seemed to behave as desired.

On 31 Jul 2019, at 12:02, John john@jdp.org.uk wrote:

I haven’t had time to look into it properly but agree that generate/publish/rewrite seems overkill. I wasn’t sure at first but according to this article https://www.impressivewebs.com/cache-busting-front-end-resources-file-name-revving-still-necessary/, query string cache busting works just fine, so that’s good!

Might be cleaner to keep the array without the query string, and append it when rendered? You already have the base version number in the boot method of BaseServiceProvider, so it could look something like this:

<link rel="stylesheet" type="text/css" href="{{ asset($path) }}?v={{ $_SERVER['BACKPACK_BASE_VERSION'] }}">

but I'm not sure this will also go well with Backpack/CRUD…

No CRUD is clearly trickier! I think it’s worth getting Base right and then moving on to thinking about that properly. A sensible first step might be to do some pruning/housekeeping… for instance if you switched to server side exports that loses quite a lot of JS.

It’s also tricker because of the amount of JS and CSS mixed in with PHP, I’m guessing from the empty create.js, crud.js, edit.js, etc. files there was a hope to address this but I realise it’s not a straightforward task. If all code was cleanly split out (including for fields, though this would require making each field a folder with a field.php, field.css and field.js file) then you’d be able to use mix with all the benefits of a proper build process… writing modern cleaner JS, handling asset loading, tree shaking and minification.

On 31 Jul 2019, at 09:29, Cristian Tabacitu <[email protected] notifications@github.com> wrote:

@johnpuddephatt https://github.com/johnpuddephatt @OliverZiegler https://github.com/OliverZiegler
That was my conclusion too. That was the best solution I could find for Backpack\Base, and I've implemented it in this PR - Laravel-Backpack/Base#385 https://github.com/Laravel-Backpack/Base/pull/385 . It has no cachebusting, though, for that please see below.

As you guys said:

Backpack maintainers use Mix, developers don't have to
we publish the bundled assets
if maintainers change CSS/JS files, new bundled files need to get published and overwrite the old ones
To overwrite public assets after each composer update, we could ask developers to add this command in their composer.json. Or we add it upon Backpack/Base and Backpack/CRUD installation:

"scripts": {
    "post-root-package-install": [
        "php -r \"copy('.env.example', '.env');\""
    ],
    "post-create-project-cmd": [
        "php artisan key:generate"
    ],
    "post-install-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postInstall"
    ],
    "post-update-cmd": [
        "Illuminate\\Foundation\\ComposerScripts::postUpdate",

  • "@php artisan vendor:publish --provider='Backpack\Base\BaseServiceProvider' --tag='public' --force",
  • "@php artisan vendor:publish --provider='Backpack\CRUD\CrudServiceProvider' --tag='public' --force",
    ],
    "post-autoload-dump": [
    "Illuminate\Foundation\ComposerScripts::postAutoloadDump",
    "@php artisan package:discover"
    ]

},

Cachebusting Solution A - Using mix()

@johnpuddephatt https://github.com/johnpuddephatt , I did NOT know that mix() had a second argument, thank you! I just tried it and added it to this PR https://github.com/Laravel-Backpack/Base/pull/387.

It sounded like a great solution, but I hit a few problems:

only public paths can be given as a second parameter (to the manifest file); ok then, we can publish the mix-manifest.json file along with the CSS and JS bundle, I said;
but the Base manifest file will NOT have the correct paths to the published items, it will have the paths to the css & js inside the vendor/backpack/base folder; so the mix() helper will not work with our mix-manifest.json file;
_we could also replace all paths in the mix-manifest.json file, one by one, according to where we published them, so that they're pointed to the correct files; but... it seems like a hack - doesn't it?
Honestly, I'm not sure using the mix() helper for cache busting makes sense as a package developer. Sound like over-engineering: we generate a mix-manifest file, then publish it, then rewrite it, only for this mix file to help with one thing - a unique string for cachebusting.

I might have another solution.

Cachebusting Solution B - Using ?v=1.x

So if we were to use the mix-manifest file as parameter, our array of css/js assets in config/backpack/base.php https://github.com/Laravel-Backpack/Base/pull/387 would have been:

// JS files that are loaded in all pages, using Laravel's mix() helper
'mix_scripts' => [

- 'packages/backpack/base/js/bundle.js',
+ 'packages/backpack/base/js/bundle.js' => 'packages/backpack/base', // asset => manifest_path
],
But since the mix() helper only helps us deal with cachebusting... why don't we manually add a version tag at the end of the file path?

// JS files that are loaded in all pages, using Laravel's asset() helper
'scripts' => [

- 'packages/backpack/base/js/bundle.js',
+ 'packages/backpack/base/js/bundle.js?v='.\PackageVersions\Versions::getVersion('backpack/base')
],
This makes the array look a bit hacky, but:

it's actually A LOT less hacky then using the mix() helper, for the Backpack maintainers;
it's easier to understand by the end-developers;
it's easy to use and customize by end-developers, including for their own assets;
What do you think?

I've updated this PR https://github.com/Laravel-Backpack/Base/pull/387 to use cache-busting solution B. If we keep B, should we maybe remove the mix_styles and mix_scripts arrays? Or maybe developers could still use them to load their own assets, bundled with Mix in the app, or other packages? Not really sure.

PS. This Laravel Mix solution works well for Backpack/Base, but I'm not sure this will also go well with Backpack/CRUD (having two big backpack.crud.bundle.js and backpack.crud.bundle.js files). I imagine including all JS plugins will make the bundle files HUGE. I'll try it after I finish all new Base features for v4 https://github.com/Laravel-Backpack/Base/pull/384.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/Laravel-Backpack/CRUD/issues/1938?email_source=notifications&email_token=AB5IVPREH6LKXDOFVKRSC4TQCFEM5A5CNFSM4IESPEG2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3GQA6Y#issuecomment-516751483, or mute the thread https://github.com/notifications/unsubscribe-auth/AB5IVPTTMAGAT54NZWB2FRLQCFEM5ANCNFSM4IESPEGQ.

Thanks @johnpuddephatt . Yes we _could_ do

<link rel="stylesheet" type="text/css" href="{{ asset($path) }}?v={{ $_SERVER['BACKPACK_BASE_VERSION'] }}">

instead of

    'scripts' => [
         'packages/backpack/base/js/bundle.js?v='.\PackageVersions\Versions::getVersion('backpack/base')
    ],

for the base files. But then developers wouldn't be able to trigger cachebusting for their custom assets (inserted in the same array) - they'd depend on the backpack/base version for cachebusting. So if they change in their custom.css which is added to the array - that will only be cachebusted when Base gets a new version.

Maybe we could have the cachebusting string as a separate config value?

    // CSS files that are loaded in all pages, using Laravel's asset() helper
    'styles' => [
-        'packages/backpack/base/css/bundle.css?v='.\PackageVersions\Versions::getVersion('backpack/base'), // includes jQuery, Bootstrap, CoreUI, PNotify, Popper
+        'packages/backpack/base/css/bundle.css', // includes jQuery, Bootstrap, CoreUI, PNotify, Popper
        //
        // examples (everything inside the bundle, loaded from CDN)
        // 'https://unpkg.com/@coreui/coreui/dist/css/coreui.min.css',
        // 'https://maxcdn.icons8.com/fonts/line-awesome/1.1/css/line-awesome-font-awesome.min.css',
        // 'https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic',
        // 'https://cdn.jsdelivr.net/npm/[email protected]/dist/PNotifyBrightTheme.css',
        //
        // overlays (design layers on top of CoreUI)
        'packages/@digitallyhappy/backstrap/css/overlay.css?v='.\PackageVersions\Versions::getVersion('backpack/base'), // Backpack's default design
    ],

    // JS files that are loaded in all pages, using Laravel's asset() helper
    'scripts' => [
-        'packages/backpack/base/js/bundle.js?v='.\PackageVersions\Versions::getVersion('backpack/base'), // includes jQuery, Bootstrap, CoreUI, PNotify, Popper
+        'packages/backpack/base/js/bundle.js', // includes jQuery, Bootstrap, CoreUI, PNotify, Popper

        // examples (everything inside the bundle, loaded from CDN)
        // 'https://code.jquery.com/jquery-3.4.1.min.js',
        // 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js',
        // 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js',
        // 'https://unpkg.com/@coreui/coreui/dist/js/coreui.min.js',
        // 'https://cdnjs.cloudflare.com/ajax/libs/pace/1.0.2/pace.min.js',
        // 'https://cdn.jsdelivr.net/npm/[email protected]/dist/iife/PNotify.js',
        // 'https://cdn.jsdelivr.net/npm/[email protected]/dist/iife/PNotifyButtons.js',

        // examples (VueJS or React)
        // 'https://unpkg.com/[email protected]/dist/vue.min.js',
        // 'https://unpkg.com/react@16/umd/react.production.min.js',
        // 'https://unpkg.com/react-dom@16/umd/react-dom.production.min.js',
    ],

+    // All JS and CSS assets defined above have this string appended as query string (?v=string).
+    // If you've want to manually trigger cachebusting for all assets in the array,
+    // Append or prepent something to the string, so that it's different. 
+   'cachebusting_string' => \PackageVersions\Versions::getVersion('backpack/base'),

Then we could do:

<link rel="stylesheet" type="text/css" href="{{ asset($path) }}?v={{ config('backpack.base.cachebusting_string') }}">

Sounds like the best of all worlds, right? No ugly array, but cachebusting string is still customizable. Any idea of a better name than cachebusting_string?

This issue has is a great point to discuss. I agree with you and I have some suggestions.

1. I totally agree remove CDN assets
Many applications are developed to run on intranet and hosted on the company's own servers. Often a good internet connection is not a priority to the company, plus the fact that in many countries there is no stable internet connection. When the client is offline the application useless.

2. Dependencies, Customization, and Custom Fields
I suggest using Laravel Mix and compiling dependencies into a single JS and CSS file.

2.1 Default
At each release of the new version, bundle the assets with the laravel mix, and in the config/backpack/crud.php file specify the file path. All vendors are published to the public folder as specified in the installation documentation. The solution for cachebusting is the release version.

2.2 Advanced developers
Some developers can need customize the application or create custom fields. In customization process maybe the developers would use dependencies that it had been loaded by CRUD bundled assets. At this point the developer can:

2.2.1. reload the dependencies that it had been loaded by CRUD because new versions could remove this depencies. Reload duplicately is to ensure the application work in case CRUD deprecated some dependency. It isn't good idea, I guess that it doesn't resolve the issue.
2.2.2. add to documention instruction specifically how to add CRUD dependencies to webpack.mix.js and use laravel mix() helper in config/backpack/crud.php file, and it solves cachebusting too.

Probably just personal preference but I'd be tempted to do:

<link rel="stylesheet" type="text/css" href="{{ asset($path) }}?v={{ config('backpack.base.cachebusting_string') ?? $_SERVER['BACKPACK_BASE_VERSION'] }}">
in the template and then comment out the cachebusting_string variable and say something like: "uncomment the line below and use it to set your own cachebusting variable. If not set the cachebusting string defaults to the current Backpack Base version number. You should only need to use this variable if making changes to CSS or JS in between Base versions."

Done! šŸŽ‰

Just pushed:

(Base and CRUD will be merged that's why we install the assets in one package and use them in the other one; they'll be merged)

In the end, with the current implementation:

  • only maintainers need to deal with NPM and Laravel Mix; the js&css files are stored entirely in the backpack package; and they get published with php artisan vendor:publish; so exactly what you proposed @promatik ;
  • we can make sure people have their assets updated by placing the php artisan vendor:publish --force command in the app's composer.json, in scripts, under post-update-cmd; @OliverZiegler I know you were worried about this;
  • cache-busting is done using a cachebusting_string in the config file, that by default has the current package version; the user can change it to force cachebusting;

I think we've gotten the best of all worlds :-) Excellent collaboration over here - thank you so much everyone. Let me know if you think something's off in those PRs. Or check it out once I make v4-beta public and you install it yourselves. If everything's ok - you should NOT notice it :-)

Thanks again.
Cheers!

can't wait to see 4.0

@parse-code here's a sneak peek šŸ˜‰ https://share.getcloudapp.com/yAuoK6xk

I'm super excited šŸ˜šŸ˜šŸ¤ø

Was this page helpful?
0 / 5 - 0 ratings