neos / neos-development-collection

The unified repository containing the Neos core packages, used for Neos development.
https://www.neos.io/
GNU General Public License v3.0
260 stars 221 forks source link

JSONP error with webpack 4 and chunk splitting in backend only #2104

Closed dtmzr closed 3 years ago

dtmzr commented 6 years ago

Description

When I use webpack 4.12.1 with the SplitChunksPlugin I get a js error (only in the backend!).

Uncaught TypeError: e is not a function
    at webpackJsonpCallback (bootstrap 57cff5fa95fb0faa0d60:19)
    at Guest.js:1

Backtracking it brings me to these lines

 var parentJsonpFunction = window["webpackJsonp"];
 window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
.
.
.
if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);

I guess the error is related to window["webpackJsonp"]. I didn't have time to investigate more but will do asap.

Steps to Reproduce

  1. Use my webpack config
  2. Add a library and entry which includes that library
  3. import the output in the template (I will make a small working snippet for that..)

Expected behavior

Shouldn't throw errors and may bind iFrame properties to own window? I guess this could make custom js mess up the backend too.

Actual behavior

Throws error and breaks interaction with UI in backend. This error does not appear when I comment out the optimization.splitChunks.cacheGroups.vendor and bundle all js into a single output. Currently the main bundle is in the body and the vendor in the head. Played around with moving them but that didn't change the behavior. Used the same code base with Webpack 2.7.0 without this behavior.

Affected Versions

Neos: 4.0.6 Neos-UI: 1.1.1

Flow: 5.0.5

Webpack config

// webpack.common.js
'use strict';

const config = require('./env.config');
const webpack = require('webpack');

module.exports = {
    entry: {
        main: ['@babel/polyfill', config.sources_dir + '/Js/main.js'],
    },
    output: {
        path: config.build_dir,
        publicPath: config.public_path,
    },
    resolve: {
        extensions: ['.js'],
        modules: ['node_modules'],
        alias: {
            'TweenLite': 'gsap/src/minified/TweenLite.min.js',
            'TweenMax': 'gsap/src/minified/TweenMax.min.js',
            'TimelineLite': 'gsap/src/minified/TimelineLite.min.js',
            'TimelineMax': 'gsap/src/minified/TimelineMax.min.js',
            'ScrollMagic': 'scrollmagic/scrollmagic/minified/ScrollMagic.min.js',
            'animation.gsap': 'scrollmagic/scrollmagic/minified/plugins/animation.gsap.min.js',
            'debug.addIndicators': 'scrollmagic/scrollmagic/minified/plugins/debug.addIndicators.min.js'
        }
    },
    module: {
        rules: [{
                test: /\.js$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }, {
                test: /\.(jpe?g|png|svg)$/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'Images/',
                        emitFile: false
                    }
                }]
            }, {
                test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'Fonts/',
                        emitFile: false
                    }
                }]
            }, {
                test: /\.json$/,
                loaders: ['json-loader']
        },]
    },
    plugins: [
        new webpack.ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery',
            jquery: 'jquery'
        })
    ]
};
// webpack.dev.js
'use strict';

const config = require('./env.config');
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = merge(common, {
    mode: 'development',
    output: {
        filename: '[name].bundle.js',
        chunkFilename: '[name].bundle.js'
    },
    module: {
        rules: [{
            test: /\.s?[ac]ss$/,
            use: [
                MiniCssExtractPlugin.loader,
                {
                    loader: 'css-loader',
                    options: {
                        sourceMap: true,
                    }
                }, {
                    loader: 'postcss-loader',
                    options: {
                        sourceMap: true,
                    }
                }, {
                    loader: 'resolve-url-loader',
                    options: {
                        sourceMap: true,
                    }
                }, {
                    loader: 'sass-loader',
                    options: {
                        sourceMap: true,
                    }
            }]
        }]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'main.css',
            chunkFilename: '[id].css'
        }),
    ],
    stats: {
        colors: true
    },
    devtool: 'inline-source-map',
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendor',
                    chunks: 'all',
                    enforce: true
                },
                styles: {
                    name: 'main',
                    test: /\.css/,
                    chunks: 'all',
                    enforce: true
                }
            }
        }
    },
});
// env.config.js
'use strict';

const path = require('path');

const PACKAGE_NAME = 'My.Website';

module.exports = {
    package_name: PACKAGE_NAME,
    build_dir: path.resolve(__dirname, `source/Packages/Sites/${PACKAGE_NAME}/Resources/Public/Assets`),
    sources_dir: path.resolve(__dirname, 'resources/'),
    public_path: `/_Resources/Static/Packages/${PACKAGE_NAME}/Assets/`,
};
// package.json
{
  "name": "my-website",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --watch --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@babel/core": "^7.0.0-beta.47",
    "@babel/polyfill": "^7.0.0-beta.51",
    "@babel/preset-env": "^7.0.0-beta.47",
    "autoprefixer": "^8.6.3",
    "babel-loader": "^8.0.0-beta",
    "bootstrap": "4.0.0",
    "clean-webpack-plugin": "^0.1.19",
    "compass-mixins": "^0.12.10",
    "css-loader": "^0.28.11",
    "cssnano": "^3.10.0",
    "extract-loader": "^2.0.1",
    "file-loader": "^1.1.11",
    "gsap": "^2.0",
    "imports-loader": "^0.8.0",
    "jquery": "^3.3.1",
    "lazysizes": "^4.0.2",
    "mini-css-extract-plugin": "^0.4.0",
    "node-sass": "^4.9.0",
    "optimize-css-assets-webpack-plugin": "^4.0.3",
    "postcss-flexbugs-fixes": "^3.3.1",
    "postcss-loader": "^2.1.5",
    "raw-loader": "^0.5.1",
    "resolve-url-loader": "^2.3.0",
    "sass-loader": "^7.0.3",
    "scrollmagic": "^2.0.5",
    "style-loader": "^0.21.0",
    "uglifyjs-webpack-plugin": "^1.2.7",
    "webpack": "^4.12.1",
    "webpack-bundle-analyzer": "^2.13.1",
    "webpack-cli": "^3.0.8",
    "webpack-merge": "^4.1.1"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "ie >= 10"
  ]
}
JanGunzenhauser commented 5 years ago

Had the same issue, found a related issue on the webpack repo: https://github.com/webpack/webpack/issues/6985

Also see: https://webpack.js.org/configuration/output/#output-jsonpfunction

output.jsonpFunction 
string

Only used when target is web, which uses JSONP for loading on-demand chunks.

A JSONP function name used to asynchronously load chunks or join multiple initial chunks (CommonsChunkPlugin, AggressiveSplittingPlugin).

This needs to be changed if multiple webpack runtimes (from different compilation) are used on the same webpage.

If using the output.library option, the library name is automatically appended.

So change output.library in webpack config to any string (will be appended to jsonpfunction to avoid conflict).

edum18 commented 5 years ago

@JanGunzenhauser thank you! it solved my problem

shivang2joshi commented 3 years ago

Update* @JanGunzenhauser

Also see: https://webpack.js.org/configuration/output/#output-jsonpfunction

This is updated after release of webpack5 in their official documentation. https://webpack.js.org/configuration/output/#outputchunkloadingglobal in webpack5 documentation this is same as jsonpFunction. Refer: https://webpack.js.org/blog/2020-10-10-webpack-5-release/#changes-to-the-structure

Thanks all, output.jsonpFunction is really helpful...

jonnitto commented 3 years ago

Can we close this one, @dtmzr?

dtmzr commented 3 years ago

@jonnitto feel free - changing the jsonp name worked as far as I remember, sorry for not replying in here - at that time I had lost total control over my notifications.