Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parcel 2 : build transpiling error #7878

Closed
safouanmatmati opened this issue Mar 30, 2022 · 0 comments · Fixed by #7886
Closed

Parcel 2 : build transpiling error #7878

safouanmatmati opened this issue Mar 30, 2022 · 0 comments · Fixed by #7886

Comments

@safouanmatmati
Copy link

safouanmatmati commented Mar 30, 2022

🐛 bug report

Parcel 2 build command doesn't transform workbox-expiration npm depenpendy package as expected.
Some this references are not handled.
There was no error with Parcel 1 and the same workbox-expiration npm package.
I found a closed issue related to this bug

🎛 Configuration (.babelrc, package.json, cli command)

My package.json

{
  "name": "my_app",
  "version": "1.0.1",
  "description": "application",
  "scripts": {
    "start": "parcel index.html --watch-for-stdin --no-autoinstall --no-hmr",
    "build": "parcel build index.html --detailed-report --no-source-maps --no-cache --no-scope-hoist --log-level verbose --no-optimize"
  },
  "dependencies": {
    "@date-io/date-fns": "^1.3.13",
    "@emotion/react": "^11.8.1",
    "@material-ui/core": "^4.12.3",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.60",
    "@material-ui/pickers": "^3.3.10",
    "@uppy/core": "^2.1.5",
    "@uppy/dashboard": "^2.1.4",
    "@uppy/file-input": "^2.0.5",
    "@uppy/react": "^2.1.2",
    "@uppy/tus": "^2.2.0",
    "@uppy/xhr-upload": "^2.0.7",
    "client-oauth2": "^4.3.3",
    "clipboard-copy": "^4.0.1",
    "date-fns": "^2.28.0",
    "deepmerge": "^4.2.2",
    "formik": "^2.2.9",
    "html-react-parser": "^1.4.8",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-gtm-module": "^2.0.11",
    "react-intersection-observer": "^8.33.1",
    "react-placeholder": "^4.1.0",
    "react-query": "^3.34.16",
    "react-router": "^6.2.1",
    "react-router-dom": "^6.2.2",
    "react-truncate-markup": "^5.1.0",
    "semver": "^7.3.5",
    "typeface-lato": "^1.1.13",
    "ua-parser-js": "^1.0.2",
    "video.js": "^7.17.0",
    "workbox-cacheable-response": "6.1.5",
    "workbox-core": "6.1.5",
    "workbox-expiration": "6.1.5",
    "workbox-precaching": "6.1.5",
    "workbox-range-requests": "6.1.5",
    "workbox-routing": "6.1.5",
    "workbox-strategies": "6.1.5",
    "yup": "^0.32.11"
  },
  "devDependencies": {
    "@babel/core": "^7.17.5",
    "@emotion/babel-plugin": "^11.7.2",
    "@emotion/eslint-plugin": "^11.7.0",
    "@parcel/packager-raw-url": "^2.4.0",
    "@parcel/packager-xml": "^2.4.0",
    "@parcel/service-worker": "^2.4.0",
    "@parcel/transformer-svg-react": "^2.4.0",
    "@parcel/transformer-webmanifest": "^2.4.0",
    "@parcel/transformer-xml": "^2.4.0",
    "browserslist-useragent-regexp": "^3.0.2",
    "buffer": "^6.0.3",
    "crypto-browserify": "^3.12.0",
    "eslint": "^8.10.0",
    "eslint-config-prettier": "^8.4.0",
    "eslint-import-resolver-parcel": "^1.10.6",
    "eslint-plugin-eslint-snake-case": "^0.0.6",
    "eslint-plugin-import": "^2.25.4",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-react": "^7.29.2",
    "eslint-plugin-react-hooks": "^4.3.0",
    "events": "^3.3.0",
    "parcel": "^2.4.0",
    "parcel-reporter-copystatic": "^1.1.0",
    "parcel-reporter-static-files-copy": "^1.3.4",
    "prettier": "2.5.1",
    "process": "^0.11.10",
    "querystring-es3": "^0.2.1",
    "stream-browserify": "^3.0.0",
    "util": "^0.12.4"
  }
}

My .parcelrc

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.svg": ["@parcel/transformer-svg-react"]
  },
  "reporters":  ["...", "parcel-reporter-copystatic"]
}

🤔 Expected Behavior

Every this references of the workbox-expiration npm depenpendy package should be handled during the build process.

😯 Current Behavior

The ReferenceError: _this is not defined error is thrown when web app is running.

service-worker.js:7702 Uncaught (in promise) ReferenceError: _this is not defined
    at _callee$ (service-worker.js:7702:29)
    at tryCatch (service-worker.js:3319:25)
    at Generator.invoke [as _invoke] (service-worker.js:3495:30)
    at Generator.next (service-worker.js:3367:29)
    at asyncGeneratorStep (service-worker.js:997:28)
    at _next (service-worker.js:1012:17)
    at service-worker.js:1017:13
    at new Promise (<anonymous>)
    at ExpirationPlugin.<anonymous> (service-worker.js:1009:16)
    at ExpirationPlugin.cachedResponseWillBeUsed (service-worker.js:7717:29)

💁 Possible Solution

It seem that _this = _this1; is missing after the build process (cf. my comments inside the code)

🔦 Context

I did an important migration of our web app from Parcel 1 to Parcel 2 to use some required new functionalities and improve the app perfomances, but we can't publish for now the new version without a working Service Worker expiration cache strategy.
We are blocked for now.

💻 Code Sample

Here the service-worker.js code that triggers the expiration strategy call, wich failed on page reload

[...]
registerRoute(
    ({ url }) =>
      url.origin === process.env.W_API_URL && /\/files\/.*/.test(url.pathname),
    new CacheFirst({
      cacheName: caches_mapping.files,
      plugins: [
        new ExpirationPlugin({
          // Cache for a maximum of 1 months
          maxAgeSeconds: 31 * 24 * 60 * 60,
        }),
      ],
    })
  );
[...]

Here the workbox-expiration npm package concerned code after a Parcel 2 build process.

[...]
function ExpirationPlugin() {
        var config = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
        var _this2 = this;
        _helpers.classCallCheck(this, ExpirationPlugin);
        var _this1 = this;
        /**
         * A "lifecycle" callback that will be triggered automatically by the
         * `workbox-strategies` handlers when a `Response` is about to be returned
         * from a [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) to
         * the handler. It allows the `Response` to be inspected for freshness and
         * prevents it from being used if the `Response`'s `Date` header value is
         * older than the configured `maxAgeSeconds`.
         *
         * @param {Object} options
         * @param {string} options.cacheName Name of the cache the response is in.
         * @param {Response} options.cachedResponse The `Response` object that's been
         *     read from a cache and whose freshness should be checked.
         * @return {Response} Either the `cachedResponse`, if it's
         *     fresh, or `null` if the `Response` is older than `maxAgeSeconds`.
         *
         * @private
         */ this.cachedResponseWillBeUsed = function() {
            var _ref = _helpers.asyncToGenerator(_regeneratorRuntimeDefault.default.mark(function _callee(param) {
                var event, request, cacheName, cachedResponse, isFresh, cacheExpiration, updateTimestampDone;
                return _regeneratorRuntimeDefault.default.wrap(function _callee$(_ctx) {
                    while(1)switch(_ctx.prev = _ctx.next){
                        case 0:
                            event = param.event, request = param.request, cacheName = param.cacheName, cachedResponse = param.cachedResponse;
                            if (cachedResponse) {
                                _ctx.next = 3;
                                break;
                            }
                            return _ctx.abrupt("return", null);
                        case 3:
//////////////////////////////////////
///////////////////// The missing code `_this = _this1;` should be there ///////////////////
//////////////////////////////////////
                            isFresh = _this._isResponseDateFresh(cachedResponse);
                            cacheExpiration = _this._getCacheExpiration(cacheName);
                            _dontWaitForJs.dontWaitFor(cacheExpiration.expireEntries());
                            updateTimestampDone = cacheExpiration.updateTimestamp(request.url);
                            if (event) try {
                                event.waitUntil(updateTimestampDone);
                            } catch (error) {}
                            return _ctx.abrupt("return", isFresh ? cachedResponse : null);
                        case 9:
                        case "end":
                            return _ctx.stop();
                    }
                }, _callee);
            }));
            return function(_) {
                return _ref.apply(this, arguments);
            };
        }();
        /**
         * A "lifecycle" callback that will be triggered automatically by the
         * `workbox-strategies` handlers when an entry is added to a cache.
         *
         * @param {Object} options
         * @param {string} options.cacheName Name of the cache that was updated.
         * @param {string} options.request The Request for the cached entry.
         *
         * @private
         */ this.cacheDidUpdate = function() {
            var _ref = _helpers.asyncToGenerator(_regeneratorRuntimeDefault.default.mark(function _callee(param) {
                var cacheName, request, _this, cacheExpiration;
                return _regeneratorRuntimeDefault.default.wrap(function _callee$(_ctx) {
                    while(1)switch(_ctx.prev = _ctx.next){
                        case 0:
                            cacheName = param.cacheName, request = param.request;
//////////////////////////////////////
///////////////////// But it was added as expected in this function ///////////////////
//////////////////////////////////////
                            _this = _this1;
                            cacheExpiration = _this1._getCacheExpiration(cacheName);
                            _ctx.next = 5;
                            return cacheExpiration.updateTimestamp(request.url);
                        case 5:
                            _ctx.next = 7;
                            return cacheExpiration.expireEntries();
                        case 7:
                        case "end":
                            return _ctx.stop();
                    }
                }, _callee);
            }));
            return function(_) {
                return _ref.apply(this, arguments);
            };
        }();
        this._config = config;
        this._maxAgeSeconds = config.maxAgeSeconds;
        this._cacheExpirations = new Map();
        if (config.purgeOnQuotaError) _registerQuotaErrorCallbackJs.registerQuotaErrorCallback(function() {
            return _this2.deleteCacheAndMetadata();
        });
    }
[...]

Here a part of the original workbox-expiration npm package code.

[...]
class ExpirationPlugin {
    /**
     * @param {Object} config
     * @param {number} [config.maxEntries] The maximum number of entries to cache.
     * Entries used the least will be removed as the maximum is reached.
     * @param {number} [config.maxAgeSeconds] The maximum age of an entry before
     * it's treated as stale and removed.
     * @param {Object} [config.matchOptions] The [`CacheQueryOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete#Parameters)
     * that will be used when calling `delete()` on the cache.
     * @param {boolean} [config.purgeOnQuotaError] Whether to opt this cache in to
     * automatic deletion if the available storage quota has been exceeded.
     */
    constructor(config = {}) {
        /**
         * A "lifecycle" callback that will be triggered automatically by the
         * `workbox-strategies` handlers when a `Response` is about to be returned
         * from a [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) to
         * the handler. It allows the `Response` to be inspected for freshness and
         * prevents it from being used if the `Response`'s `Date` header value is
         * older than the configured `maxAgeSeconds`.
         *
         * @param {Object} options
         * @param {string} options.cacheName Name of the cache the response is in.
         * @param {Response} options.cachedResponse The `Response` object that's been
         *     read from a cache and whose freshness should be checked.
         * @return {Response} Either the `cachedResponse`, if it's
         *     fresh, or `null` if the `Response` is older than `maxAgeSeconds`.
         *
         * @private
         */
        this.cachedResponseWillBeUsed = async ({ event, request, cacheName, cachedResponse }) => {
            if (!cachedResponse) {
                return null;
            }
            const isFresh = this._isResponseDateFresh(cachedResponse);
            // Expire entries to ensure that even if the expiration date has
            // expired, it'll only be used once.
            const cacheExpiration = this._getCacheExpiration(cacheName);
            dontWaitFor(cacheExpiration.expireEntries());
            // Update the metadata for the request URL to the current timestamp,
            // but don't `await` it as we don't want to block the response.
            const updateTimestampDone = cacheExpiration.updateTimestamp(request.url);
            if (event) {
                try {
                    event.waitUntil(updateTimestampDone);
                }
                catch (error) {
                    if (process.env.NODE_ENV !== 'production') {
                        // The event may not be a fetch event; only log the URL if it is.
                        if ('request' in event) {
                            logger.warn(`Unable to ensure service worker stays alive when ` +
                                `updating cache entry for ` +
                                `'${getFriendlyURL(event.request.url)}'.`);
                        }
                    }
                }
            }
            return isFresh ? cachedResponse : null;
        };
[...]

🌍 Your Environment

Software Version(s)
Parcel 2.4.0
Node 14.19.0
npm/Yarn 8.5.1
Operating System Linux
$ ./npm.sh version
{
  my_app: '1.0.1',
  npm: '8.5.1',
  node: '14.19.0',
  v8: '8.4.371.23-node.85',
  uv: '1.42.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '83',
  nghttp2: '1.42.0',
  napi: '8',
  llhttp: '2.1.4',
  openssl: '1.1.1m',
  cldr: '40.0',
  icu: '70.1',
  tz: '2021a3',
  unicode: '14.0'
}

Thank you very much for your work and any help.

image

@safouanmatmati safouanmatmati changed the title Parcel 2: ReferenceError: _this is not defined Parcel 2 : build transpiling error Mar 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants