parcel-bundler / parcel

The zero configuration build tool for the web. πŸ“¦πŸš€
https://parceljs.org
MIT License
43.5k stars 2.27k forks source link

Build fails when cache is empty, and succeeds next time ("does not export") #7272

Closed vcarel closed 2 years ago

vcarel commented 3 years ago

πŸ› bug report

Build fails when the cache is empty. It works on 2nd try.

πŸŽ› Configuration (.babelrc, package.json, cli command)

No .babelrc

tsconfig.json ```json { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "allowJs": true, "allowSyntheticDefaultImports": true, "baseUrl": ".", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "react-jsx", "lib": ["dom", "dom.iterable", "esnext"], "module": "esnext", "moduleResolution": "node", "noEmit": true, "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, "skipLibCheck": true, "strict": false, "target": "es2021" }, "include": ["src"] } ```
package.json ```json { "private": true, "homepage": "/", "dependencies": { "@auth0/auth0-react": "^1.6.0", "@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/pro-duotone-svg-icons": "^5.15.4", "@fortawesome/pro-light-svg-icons": "^5.15.4", "@fortawesome/pro-regular-svg-icons": "^5.15.4", "@fortawesome/pro-solid-svg-icons": "^5.15.4", "@fortawesome/react-fontawesome": "^0.1.15", "@hookform/error-message": "^2.0.0", "@hookform/resolvers": "^2.8.0", "@popperjs/core": "^2.9.3", "@reduxjs/toolkit": "^1.6.1", "@sentry/browser": "^6.11.0", "@sentry/react": "^6.11.0", "@stripe/react-stripe-js": "^1.4.1", "@stripe/stripe-js": "^1.17.1", "async-mutex": "^0.3.1", "bulma": "^0.9.3", "bulma-steps": "^2.2.1", "date-fns": "^2.24.0", "date-fns-tz": "^1.1.6", "dexie": "^3.0.3", "highcharts": "^9.2.2", "highcharts-react-official": "^3.0.0", "lodash-es": "^4.17.21", "mapbox-gl": "1.13.0", "moment": "^2.29.1", "pica": "^7.1.0", "qrcode.react": "^1.0.1", "react": "^17.0.2", "react-dates": "^21.8.0", "react-dnd": "^14.0.3", "react-dnd-html5-backend": "^14.0.1", "react-dom": "^17.0.2", "react-easy-crop": "^3.5.2", "react-error-boundary": "^3.1.3", "react-highlight-words": "^0.17.0", "react-hook-form": "^7.13.0", "react-hotjar": "^3.0.1", "react-json-view": "^1.21.3", "react-popper": "^2.2.5", "react-query": "^3.26.0", "react-redux": "^7.2.4", "react-router-dom": "^5.3.0", "react-select": "^4.3.1", "react-swipeable": "^6.2.0", "react-toastify": "^7.0.4", "react-with-direction": "^1.3.1", "redux": "^4.1.1", "typescript": "^4.4.4", "yup": "^0.32.9" }, "lint-staged": { "*.+(js|jsx)": [ "eslint --fix" ], "*.scss": [ "stylelint --fix" ], "*.+(json|css|md)": [ "prettier --write" ] }, "alias": { "src": "./src" }, "source": "public/index.html", "scripts": { "analyze": "source-map-explorer build/static/js/*.js", "start": "parcel --port 3000 --open --dist-dir build", "sentry-release": "node ./sentry.js", "build": "parcel build --dist-dir build", "test": "jest", "typecheck": "tsc --noEmit", "lint": "eslint . && stylelint \"src/**/*.scss\"", "lintfix": "eslint --fix . && stylelint --fix \"src/**/*.scss\"", "postinstall": "rimraf .eslintcache", "serve": "serve -s build/ -p 3000", "prepare": "cd .. && husky install" }, "stylelint": { "extends": [ "stylelint-config-sass-guidelines", "stylelint-config-recess-order" ], "ignoreFiles": [ "**/*.js" ], "rules": { "function-parentheses-space-inside": null, "max-nesting-depth": null, "order/properties-alphabetical-order": null, "selector-max-compound-selectors": null, "scss/at-function-pattern": null, "scss/at-import-no-partial-leading-underscore": null, "scss/dollar-variable-pattern": null, "selector-class-pattern": null, "selector-no-qualifying-type": null, "string-quotes": null } }, "browserslist": { "production": [ ">0.5%", "last 2 chrome version", "last 2 firefox version", "last 2 safari version", "last 2 edge version", "not dead", "not op_mini all", "not ie > 0" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version", "last 1 edge version" ] }, "devDependencies": { "@babel/core": "^7.16.0", "@babel/preset-env": "^7.16.0", "@babel/preset-typescript": "^7.16.0", "@babel/runtime": "^7.16.0", "@parcel/packager-raw-url": "^2.0.1", "@parcel/transformer-sass": "^2.0.1", "@parcel/transformer-webmanifest": "^2.0.1", "@sentry/cli": "^1.68.0", "@sentry/webpack-plugin": "^1.17.1", "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.0.2", "@types/node": "^16.11.6", "@types/react": "^17.0.34", "@types/react-dom": "^17.0.11", "@typescript-eslint/eslint-plugin": "^5.3.0", "@typescript-eslint/parser": "^5.3.0", "babel-eslint": "^10.1.0", "babel-plugin-module-resolver": "^4.1.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-config-react-app": "^6.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-flowtype": "^5.9.0", "eslint-plugin-import": "^2.25.2", "eslint-plugin-jsx-a11y": "^6.3.1", "eslint-plugin-prettier": "^3.4.1", "eslint-plugin-react": "^7.26.1", "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-sort-keys-fix": "^1.1.2", "husky": "^7.0.4", "jest": "^27.3.1", "lint-staged": "^11.2.6", "mock-file-server": "^0.1.17", "node-sass": "^6.0.1", "parcel": "^2.0.1", "prettier": "^2.4.1", "rimraf": "^3.0.2", "serve": "^13.0.2", "source-map-explorer": "^2.5.2", "stylelint": "^14.0.1", "stylelint-config-recess-order": "^2.5.0", "stylelint-config-sass-guidelines": "^9.0.1", "ts-node": "^10.4.0" } } ```

πŸ€” Expected Behavior

It should build at first try.

😯 Current Behavior

It builds at 2nd try.

First try:

$ rm -rf .parcel-cache

$ parcel build --dist-dir build
🚨 Build failed.
RangeError: Invalid count value
    at String.repeat (<anonymous>)
    at codeFrame (/home/vianney/myproject/node_modules/@parcel/codeframe/lib/codeframe.js:214:44)
    at prettyDiagnostic (/home/vianney/myproject/node_modules/@parcel/utils/lib/prettyDiagnostic.js:104:55)
    at async writeDiagnostic (/home/vianney/myproject/node_modules/@parcel/reporter-cli/lib/CLIReporter.js:207:9)
    at async _report (/home/vianney/myproject/node_modules/@parcel/reporter-cli/lib/CLIReporter.js:151:7)
    at async ReporterRunner.report (/home/vianney/myproject/node_modules/@parcel/core/lib/ReporterRunner.js:105:11)
    at async Parcel._build (/home/vianney/myproject/node_modules/@parcel/core/lib/Parcel.js:464:7)
    at async Parcel.run (/home/vianney/myproject/node_modules/@parcel/core/lib/Parcel.js:275:18)
    at async run (/home/vianney/myproject/node_modules/parcel/lib/cli.js:374:7)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

2nd try:

$ parcel build --dist-dir build
✨ Built in 96.07s

build/index.html                                             811 B     6.79s
build/favicon.b44c799f.ico                                   651 B     347ms
build/manifest.webmanifest                                   256 B     859ms
build/index.dce671b8.js                                ⚠️  2.97 MB    85.55s
build/card-unknown.73c552ba.svg                              174 B     6.77s
build/eventlog.5e6b5a96.svg                                  333 B    85.70s
build/breakdown-placeholder.af70f0da.svg                     849 B     6.77s
build/chart-no-data.07e536b7.svg                           1.92 KB    85.70s
build/illustration-analysis.003c1851.svg                   4.14 KB     7.03s
build/condition-always.91f9f0c9.svg                        20.2 KB    85.70s
build/condition-device.e0a78b04.svg                          35 KB     6.77s
build/condition-external-api--disabled.be1effc8.svg       12.69 KB    85.70s
build/condition-geolocation.f75ada13.svg                 202.74 KB     6.77s
build/condition-identifier.5404e4dc.svg                   16.54 KB    85.70s
build/condition-query--disabled.b458dee4.svg              11.17 KB     6.77s
build/condition-recurrence.3dd0169c.svg                   15.49 KB    85.70s
build/condition-time.7315c634.svg                         16.49 KB     6.77s
build/illustration-calendar.45969fe6.svg                  16.11 KB    85.70s
build/quortex-io.09692677.svg                              5.68 KB     7.03s
build/illustration-rules.d826a365.svg                     25.04 KB    85.70s
build/index.fc247a88.css                                 502.09 KB     7.04s
build/noto-serif-v9-latin-regular.64635b43.woff2          23.36 KB     342ms
build/noto-serif-v9-latin-regular.f31a9557.woff           27.06 KB     858ms
build/noto-serif-v9-latin-700.cce4f4c7.woff2               26.7 KB     342ms
build/noto-serif-v9-latin-700.cb2a891a.woff               30.71 KB     858ms
build/roboto-v20-latin-300.81a5bc04.woff2                 15.41 KB     342ms
build/roboto-v20-latin-300.9527f5b1.woff                  19.87 KB     859ms
build/roboto-v20-latin-regular.962f1284.woff2             15.37 KB     341ms
build/roboto-v20-latin-regular.541b858a.woff              19.79 KB     858ms
build/roboto-v20-latin-500.b3c683d1.woff2                  15.5 KB     342ms
build/roboto-v20-latin-500.5f8bfa54.woff                  19.98 KB     858ms
build/roboto-v20-latin-700.41e719aa.woff2                 15.45 KB     342ms
build/roboto-v20-latin-700.f439c182.woff                  19.88 KB     858ms
build/roboto-mono-v12-latin-regular.cf1eee5f.woff2        12.02 KB     341ms
build/roboto-mono-v12-latin-regular.fe08f47b.woff          14.8 KB     857ms
build/roboto-mono-v12-latin-700.447ac127.woff2               12 KB     341ms
build/roboto-mono-v12-latin-700.975b2291.woff             14.88 KB     858ms
build/index.45cb35ff.js                                ⚠️  2.97 MB    85.55s
build/card-unknown.73c552ba.svg                              174 B     6.76s
build/eventlog.5e6b5a96.svg                                  333 B    85.69s
build/breakdown-placeholder.af70f0da.svg                     849 B     6.76s
build/chart-no-data.07e536b7.svg                           1.92 KB    85.69s
build/illustration-analysis.003c1851.svg                   4.14 KB     7.02s
build/condition-always.91f9f0c9.svg                        20.2 KB    85.69s
build/condition-device.e0a78b04.svg                          35 KB     6.76s
build/condition-external-api--disabled.be1effc8.svg       12.69 KB    85.69s
build/condition-geolocation.f75ada13.svg                 202.74 KB     6.76s
build/condition-identifier.5404e4dc.svg                   16.54 KB    85.69s
build/condition-query--disabled.b458dee4.svg              11.17 KB     6.76s
build/condition-recurrence.3dd0169c.svg                   15.49 KB    85.69s
build/condition-time.7315c634.svg                         16.49 KB     6.76s
build/illustration-calendar.45969fe6.svg                  16.11 KB    85.69s
build/quortex-io.09692677.svg                              5.68 KB     7.02s
build/illustration-rules.d826a365.svg                     25.04 KB    85.69s
Done in 97.80s.

πŸ’ Possible Solution

Something seems to be wrong with codeFrame / prettyDiagnostic.

Not a solution but a work-around: run the build twice πŸ˜… e.g. in package.json:

  "scripts": {
     "build": "parcel build; parcel build",
  }

πŸ”¦ Context

I'm trying to migrate quite a big app from create-react-app to parcel.

It happened when I replaced all my import styles from by import * as styles as suggested in parcel's warnings about treeshaking. When I revert this change, it works fine.

πŸ’» Code Sample

I can't share my code sorry :-/

🌍 Your Environment

Software Version(s)
Parcel 2.0.1
Node 16.13.0
yarn 1.22.15
Operating System Ubuntu 21.10 - 64 bits
mischnic commented 3 years ago

Can you go to this line:

/home/vianney/myproject/node_modules/@parcel/codeframe/lib/codeframe.js:214:44

and comment it out? It should look like this highlightLine += highlighter('^'.repeat(characters))

Then you should hopefully at least see the actual error.

vcarel commented 3 years ago

Hi @mischnic, we had the same idea at the same time ^^

I just found the error! Parcel wanted to tell me that I was using a style which was undefined in my CSS module (for the record, it's in a JS file - that's why I didn't noticed it before)

The file is 294 lines long. The offending code was at line 249:

diff --git a/front/src/App/Main/Account/index.js b/front/src/App/Main/Account/index.js
index 0f5cb8d0..7337409d 100644
--- a/front/src/App/Main/Account/index.js
+++ b/front/src/App/Main/Account/index.js
@@ -249,7 +249,7 @@ const Account = ({ userUuid }) => {
                   </li>
                 </ul>
               </nav>
-              <div className={styles.tabContent}>
+              <div>
                 <div className={tab === "profile" ? null : "is-hidden"}>
                   <ProfileTab setPendingChanges={setPendingChanges} user={user} />
                 </div>
mischnic commented 3 years ago

Regarding the prettyDiagnostic problem: are you using a babelrc file or Flow?

Did I understand correctly that the error was actually correct and the bug is that is builds successfully on subsequent runs even though it should still fail?

vcarel commented 3 years ago

I don't have any babelrc or Flow. Just a few Typescript files, and Javascript files for the rest. The offending file was a JS one.

Did I understand correctly that the error was actually correct and the bug is that is builds successfully on subsequent runs even though it should still fail?

You are correct for the first part: the error was actually correct. However for the second part, I wouldn't expect the build to fail for just a warning.

To rephrase the observed behavior: the first time the file is built, the warning pops up and makes parcel to fail. The second time, the file is already built, and since there's no other warnings of that kind, it passes.

mischnic commented 3 years ago

The error here is the same error as the foo.js does not export 'something' error you get for JS-to-JS imports. And they should persist - they are also used for JS and CSS modules tree shaking.

I can reproduce that error-rebuild-success problem. It would be great if you could try to reduce the file causing the RangeError: Invalid count value error until you can share it.

vcarel commented 3 years ago

Sure, I'll do that tomorrow. It's midnight here already πŸŒƒ. Thanks for your help ! 😊

vcarel commented 3 years ago

@mischnic Here it is πŸ™‚

src/App/Main/Account/index.js ```jsx import { yupResolver } from "@hookform/resolvers/yup" import PropTypes from "prop-types" import { useEffect, useState } from "react" import { FormProvider } from "react-hook-form" import { useHistory, useRouteMatch } from "react-router-dom" import { toast } from "react-toastify" import ApiErrorToast from "src/components/ApiErrorToast" import ErrorMessage from "src/components/ErrorMessage" import SaveSuccessToast from "src/components/SaveSuccessToast" import ModalCloseButton from "src/components/buttons/ModalCloseButton" import { getCroppedSquareImg } from "src/helpers/image" import { useApi } from "src/hooks/api" import { useAutoResetForm, useSetApiErrors } from "src/hooks/form" import { useModalContext } from "src/hooks/modal" import { useMe, useOrganizationMember, useDeleteOrganizationMemberDelayCleanup, useUpdateOrganizationMember, useValidateOrganizationMember, } from "src/queries/Organization" import { useUpdatePoolMember, useDeletePoolMember } from "src/queries/Pools" import ConfirmChanges from "./ConfirmChanges" import PoolsTab from "./PoolsTab" import ProfileTab from "./ProfileTab" import * as styles from "./index.module.scss" import { schema } from "./yupSchema" const Account = ({ userUuid }) => { const { close, setBackgroundDismiss } = useModalContext() const history = useHistory() const match = useRouteMatch("/pools/:poolUuid") const poolUuid = match?.params.poolUuid const { data: me } = useMe() const { data: user } = useOrganizationMember(userUuid) const { mutateAsync: updatePoolMember } = useUpdatePoolMember() const { mutateAsync: deletePoolMember } = useDeletePoolMember() const { uploadFile } = useApi() const [tab, setTab] = useState("profile") const [pendingChanges, setPendingChanges] = useState() const form = useAutoResetForm({ defaultValues: user, resolver: yupResolver(schema, { stripUnknown: true }), }) const { formState, handleSubmit } = form const { errors, isDirty, isSubmitting } = formState const setApiErrors = useSetApiErrors(form) const { mutateAsync: updateOrganizationMember } = useUpdateOrganizationMember(user.uuid) const { mutateAsync: deleteOrganizationMember } = useDeleteOrganizationMemberDelayCleanup( user.uuid ) const { mutateAsync: validateOrganizationMember } = useValidateOrganizationMember(userUuid) const isMyself = userUuid === me.uuid useEffect(() => { setBackgroundDismiss(!isDirty) }, [isDirty, setBackgroundDismiss]) const onSubmit = data => { if ( (isMyself && data.pools.find(p => !!p.prevAccess)) || data.pools.find(p => p.access === "remove") ) { setPendingChanges(data) } else { return apply(data) } } const apply = async submitData => { try { const { pools, invitation, photoUpload, ...member } = submitData // First update pools, because it depends on role // And upload photo too, because this API will update user profile with the uploaded photo const toRemove = pools.filter(p => p.access === "remove") const toUpdate = pools.filter(p => p.prevAccess && p.access !== "remove") await Promise.all([ ...toRemove.map(p => deletePoolMember({ isMyself, poolUuid: p.poolUuid, userUuid: user.uuid }) ), ...toUpdate.map(p => updatePoolMember({ access: p.access, poolUuid: p.poolUuid, userUuid: user.uuid, }) ), ...(photoUpload.image ? [ uploadFile( "/image/profile_picture/", await getCroppedSquareImg(photoUpload.image, photoUpload.croppedAreaPixels) ), ] : []), ]) // Then update user profile, including its role await updateOrganizationMember(member) close() if (isMyself && toRemove.find(p => p.poolUuid === poolUuid)) { history.push("/pools/") } } catch (e) { if (e.status >= 400 && e.status < 500) { setApiErrors(e.jsonData) } else { toast.error() setPendingChanges(undefined) } } } const suspendAccount = async suspended => { try { await updateOrganizationMember({ suspended }) } catch (e) { toast.error() } setPendingChanges(undefined) } const deleteAccount = async () => { try { await deleteOrganizationMember() close() toast.success( {user.name || user.email} ’s account has been successfully deleted } /> ) } catch (e) { toast.error() setPendingChanges(undefined) } } const revokeInvitation = async () => { try { await deleteOrganizationMember() close() toast.success( The invitation of {user.name || user.email} has been revoked } /> ) } catch (e) { toast.error() setPendingChanges(undefined) } } const acceptInvitationRequest = async () => { try { await validateOrganizationMember() } catch (e) { toast.error() } setPendingChanges(undefined) } const declineInvitationRequest = async () => { try { await deleteOrganizationMember() close() toast.success( The invitation of {user.name || user.email} has been declined } /> ) } catch (e) { toast.error() setPendingChanges(undefined) } } return (
{pendingChanges && ( setPendingChanges(undefined), onConfirm: () => { if (pendingChanges.pools) { apply(pendingChanges) } else if (pendingChanges.action) { switch (pendingChanges.action) { case "suspend_account": return suspendAccount(true) case "activate_account": return suspendAccount(false) case "delete_account": return deleteAccount() case "revoke_invitation": return revokeInvitation() case "accept_invitation_request": return acceptInvitationRequest() case "decline_invitation_request": return declineInvitationRequest() default: return } } }, pendingChanges, user, }} /> )}
Account
{isDirty && ( <> )}
{errors.detail && (
)}
) } Account.propTypes = { onClose: PropTypes.func.isRequired, userUuid: PropTypes.string.isRequired, } export default Account ```
mischnic commented 3 years ago

Perfect, thanks! I've opened another issue for the prettyDiagnostic problem: https://github.com/parcel-bundler/parcel/issues/7278

vcarel commented 3 years ago

Excellent! I'm closing this one then. Thanks again !

mischnic commented 3 years ago

Let's keep this one open for the bug that the error goes away on rebuilds: https://github.com/parcel-bundler/parcel/issues/7272#issuecomment-964621113