Prestashop: Webpack encore support or basic theme updates.

Created on 8 Jan 2019  路  6Comments  路  Source: PrestaShop/PrestaShop

Is your feature request related to a problem? Please describe.
I am bad at webpack so i usually use webpack encore. The best feature from that is the versioning of the output files. The rest is also useful, not to have to write the configs for the entire setup and develop wilt local source maps and other helpful things.
https://symfony.com/blog/introducing-webpack-encore-for-asset-management

...

But is does not work with basic presta theme setup.

Describe the solution you'd like
So what i did, i added an empty theme.css and theme.js so the theme is installable. Next to the asset folder i build a build folder for my webpack encore.

Encore
  .setOutputPath('./../build/')
  .setPublicPath('/themes/polytex-theme/build')
  .setManifestKeyPrefix('./themes/polytex-theme/build')
  .addEntry('theme', './js/theme.js')
  .enableVersioning()
  ...
  ...

const config = Encore.getWebpackConfig();

config.externals = {
  prestashop: 'prestashop',
  $: '$',
  jquery: 'jQuery',
};

module.exports = config;

Link new assets in the theme.yml

assets:
    css:
        all:
            -   id: cat-theme-lib
                path: build/theme.css
    js:
        all:
            -   id: runtime
                path: build/runtime.js
            -   id: cat-theme-lib
                path: build/theme.js

And add a simple hook after styles are loaded:

public function hookActionFrontControllerSetMedia()
{
    $assets = $this->context->shop->theme->getPageSpecificAssets($this->context->controller->php_self);

    foreach ($assets['css'] as $css) {
        $newPath = $this->getNewFilePath($css);
        if ($newPath) {
            $this->context->controller->registerStylesheet($css['id'], $newPath, $css);
        }
    }

    foreach ($assets['js'] as $js) {
        $newPath = $this->getNewFilePath($js);
        if ($newPath) {
            $this->context->controller->registerJavascript($js['id'], $newPath, $js);
        }
    }
}

/**
 * @param array $obj
 *
 * @return bool|string
 */
public function getNewFilePath($obj)
{
    if ($obj['inline']) {
        return false;
    }
    if (false === array_keys($obj, 'path')) {
        return false;
    }

    $path = $obj['path'];
    $folder = dirname(_PS_THEME_DIR_ . $path);

    $manifestFile = $folder . '/manifest.json';
    if (false === is_file($manifestFile)) {
        return false;
    }

    $sha = sha1_file($manifestFile);
    if (false === isset($this->manifestFiles[$sha])) {
        $this->manifestFiles[$sha] = json_decode(file_get_contents($manifestFile), true);
    }

    $manifest = $this->manifestFiles[$sha];
    $originalFilePath = '.' . _THEME_DIR_ . $path;
    if (!isset($manifest[$originalFilePath])) {
        return false;
    }

    if (trim($originalFilePath, '.') === $manifest[$originalFilePath]) {
        return false;
    }

    return dirname($path) . '/' . basename($manifest[$originalFilePath]);
}

Describe alternatives you've considered
I was planning on writing all the options in an optional webpack config. But i got stuck in webpack config land so i got out of that again.

Additional context
Is there a planning to upgrade a way of building the styles and/or how to set up a theme. Or is the way of classic/classic-rocket updates the way to go? They are both stuck on webpack 2.x. Or should theme builders setup there own thing, like they should and could.

So any opinions?

Improvement

Most helpful comment

Webpack is not hard to understand the documentation is really well explained :sweat_smile:
I really think using PHP to build Webpack configuration is overkill and will decrease performance.
We are sorry but we don't plan to add this kind of tool in PrestaShop.

All 6 comments

HI @casperh1nl,

Thanks for your report.
@PrestaShop/prestashop-core-developers, @eternoendless what do you think about his suggestion?
Thanks!

I'm also interested in reading manifest.json file not for webpack encore but pure webpack config.

There's also a way given by @kermorgant in this SO post
https://stackoverflow.com/questions/48258620/module-of-prestashop-and-webpack
It's more a controller module way to load assets contained in a manifest.json file.

Anyway It could be a very good improvement to be able to read manifest.json in a simple way so we could be able to manage assets versioning.

This could be a line in theme.yml, like :

assets:
  use_manifest_file : yes

Yes, also in newer webpack encores webpack can split more code for faster loading. So yes, now that has to be done like that.

Hi @psyray,

Would you be willing to make a pull request on GitHub with your code suggestion?
https://github.com/PrestaShop/PrestaShop/tree/develop
Thank you!

It uses the entry from the webpack encore config

.addEntry('theme', './js/theme.js')

And you can split your files

.enableSingleRuntimeChunk()
.splitEntryChunks()

Yaml setup

assets:
    webpack_encore:
        entrypoints: build/entrypoints.json
        entry: theme

Functions.

public function hookActionFrontControllerSetMedia()
{
    $webpackEncore = $this->context->shop->theme->get('assets.webpack_encore');

    if ($webpackEncore) {
        $this->loadEncoreEntrypoints($webpackEncore);
    }
}

public function loadEncoreEntrypoints(array $webpackEncore)
{
    if (false === isset($webpackEncore['entrypoints'], $webpackEncore['entry'])) {
        return;
    }

    $entrypoints = $webpackEncore['entrypoints'];
    $entry = $webpackEncore['entry'];
    $entrytpointsFile = _PS_THEME_DIR_ . $entrypoints;
    if (false === is_file($entrytpointsFile)) {
        return;
    }

    $entrytpoints = json_decode(file_get_contents($entrytpointsFile), true);
    if (false === array_key_exists('entrypoints', $entrytpoints) || false === array_key_exists($entry, $entrytpoints['entrypoints'])) {
        return;
    }

    foreach ($entrytpoints['entrypoints'][$entry] as $type => $list) {
        foreach ($list as $key => $fileName) {
            if ($type === 'js') {
                $this->context->controller->registerJavascript('webpack-encore-' . $key, $fileName);
            }

            if ($type === 'css') {
                $this->context->controller->registerStylesheet('webpack-encore-' . $key, $fileName);
            }
        }
    }
}

:+1:

Webpack is not hard to understand the documentation is really well explained :sweat_smile:
I really think using PHP to build Webpack configuration is overkill and will decrease performance.
We are sorry but we don't plan to add this kind of tool in PrestaShop.

Was this page helpful?
0 / 5 - 0 ratings