Repository: gregberge/loadable-components Branch: main Commit: 18544decdd0e Files: 252 Total size: 364.2 KB Directory structure: gitextract_pnucyiln/ ├── .eslintignore ├── .eslintrc.json ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.md │ │ ├── feature.md │ │ ├── question.md │ │ └── regression.md │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── SUPPORT.md │ ├── opencollective.yml │ └── stale.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── BACKERS.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── examples/ │ ├── client-side/ │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── A.js │ │ │ ├── B.js │ │ │ ├── Hello.js │ │ │ └── index.js │ │ └── webpack.config.js │ ├── razzle/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── About/ │ │ │ └── index.js │ │ ├── App.css │ │ ├── App.js │ │ ├── Contact/ │ │ │ └── index.js │ │ ├── Home/ │ │ │ ├── Home.css │ │ │ ├── Intro.js │ │ │ ├── Logo.js │ │ │ ├── Welcome.js │ │ │ └── index.js │ │ ├── NotFound/ │ │ │ └── index.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── server-side-rendering/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── App.js │ │ │ │ ├── Y/ │ │ │ │ │ └── file.js │ │ │ │ ├── letters/ │ │ │ │ │ ├── A.css │ │ │ │ │ ├── A.js │ │ │ │ │ ├── B.js │ │ │ │ │ ├── C.js │ │ │ │ │ ├── D.js │ │ │ │ │ ├── E.js │ │ │ │ │ ├── F.js │ │ │ │ │ ├── G.js │ │ │ │ │ └── Z/ │ │ │ │ │ └── file.js │ │ │ │ ├── main-node.js │ │ │ │ ├── main-web.js │ │ │ │ └── main.css │ │ │ └── server/ │ │ │ └── main.js │ │ └── webpack.config.babel.js │ ├── server-side-rendering-async-node/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── App.js │ │ │ │ ├── Y/ │ │ │ │ │ └── file.js │ │ │ │ ├── letters/ │ │ │ │ │ ├── A.css │ │ │ │ │ ├── A.js │ │ │ │ │ ├── B.js │ │ │ │ │ ├── C.js │ │ │ │ │ ├── D.js │ │ │ │ │ ├── E.js │ │ │ │ │ ├── F.js │ │ │ │ │ ├── G.js │ │ │ │ │ └── Z/ │ │ │ │ │ └── file.js │ │ │ │ ├── main-async-node.js │ │ │ │ ├── main-web.js │ │ │ │ └── main.css │ │ │ └── server/ │ │ │ └── main.js │ │ └── webpack.config.babel.js │ ├── suspense/ │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Hello.js │ │ │ └── index.js │ │ └── webpack.config.js │ ├── typescript/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── App.tsx │ │ │ │ ├── Page.tsx │ │ │ │ ├── PageWithParam.tsx │ │ │ │ ├── main-node.js │ │ │ │ └── main-web.js │ │ │ └── server/ │ │ │ └── main.js │ │ ├── tsconfig.json │ │ └── webpack.config.babel.js │ └── webpack/ │ ├── README.md │ ├── webpack4/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── App.js │ │ │ │ ├── letters/ │ │ │ │ │ ├── A.css │ │ │ │ │ ├── A.js │ │ │ │ │ ├── B.js │ │ │ │ │ ├── C.js │ │ │ │ │ └── D.js │ │ │ │ ├── main-node.js │ │ │ │ └── main-web.js │ │ │ └── server/ │ │ │ └── main.js │ │ └── webpack.config.babel.js │ └── webpack5/ │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── nodemon.json │ ├── package.json │ ├── src/ │ │ ├── client/ │ │ │ ├── App.js │ │ │ ├── letters/ │ │ │ │ ├── A.css │ │ │ │ ├── A.js │ │ │ │ ├── B.js │ │ │ │ ├── C.js │ │ │ │ └── D.js │ │ │ ├── main-node.js │ │ │ └── main-web.js │ │ └── server/ │ │ └── main.js │ └── webpack.config.babel.js ├── lerna.json ├── netlify.toml ├── package.json ├── packages/ │ ├── babel-plugin/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ └── src/ │ │ ├── __snapshots__/ │ │ │ └── index.test.js.snap │ │ ├── index.js │ │ ├── index.test.js │ │ ├── properties/ │ │ │ ├── chunkName.js │ │ │ ├── importAsync.js │ │ │ ├── isReady.js │ │ │ ├── requireAsync.js │ │ │ ├── requireSync.js │ │ │ ├── resolve.js │ │ │ └── state.js │ │ └── util.js │ ├── codemod/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── bin/ │ │ │ ├── main.js │ │ │ └── utils/ │ │ │ └── CodemodError.js │ │ ├── package.json │ │ └── transforms/ │ │ ├── __testfixtures__/ │ │ │ ├── react-loadable-to-loadable-component_arrow-no-params.input.js │ │ │ ├── react-loadable-to-loadable-component_arrow-no-params.output.js │ │ │ ├── react-loadable-to-loadable-component_arrow-w-params.input.js │ │ │ ├── react-loadable-to-loadable-component_arrow-w-params.output.js │ │ │ ├── react-loadable-to-loadable-component_expr.input.js │ │ │ └── react-loadable-to-loadable-component_expr.output.js │ │ ├── __tests__/ │ │ │ └── react-loadable-to-loadable-component-test.js │ │ └── react-loadable-to-loadable-component.js │ ├── component/ │ │ ├── .npmignore │ │ ├── .size-snapshot.json │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── rollup.config.js │ │ └── src/ │ │ ├── Context.js │ │ ├── createLoadable.js │ │ ├── index.js │ │ ├── library.js │ │ ├── loadable.js │ │ ├── loadable.test.js │ │ ├── loadableReady.js │ │ ├── resolvers.js │ │ ├── shared.js │ │ ├── sharedInternals.js │ │ └── util.js │ ├── server/ │ │ ├── .npmignore │ │ ├── .size-snapshot.json │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __fixtures__/ │ │ │ └── stats.json │ │ ├── package.json │ │ ├── rollup.config.js │ │ └── src/ │ │ ├── ChunkExtractor.js │ │ ├── ChunkExtractor.test.js │ │ ├── ChunkExtractorManager.js │ │ ├── index.js │ │ ├── sharedInternals.js │ │ ├── util.js │ │ └── util.test.js │ └── webpack-plugin/ │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src/ │ └── index.js ├── resources/ │ └── loadable-components.sketch ├── scripts/ │ ├── copy-stats-fixture.js │ ├── git-release.sh │ └── prepare.sh └── website/ ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── README.md ├── _redirects ├── gatsby-config.js ├── gatsby-node.js ├── package.json └── src/ └── pages/ ├── docs/ │ ├── api-loadable-component.mdx │ ├── api-loadable-server.mdx │ ├── api-loadable-webpack-plugin.mdx │ ├── babel-plugin.mdx │ ├── code-splitting.mdx │ ├── component-splitting.mdx │ ├── delay.mdx │ ├── dynamic-import.mdx │ ├── error-boundaries.mdx │ ├── fallback.mdx │ ├── faq.mdx │ ├── getting-started.mdx │ ├── library-splitting.mdx │ ├── loadable-vs-react-lazy.mdx │ ├── migrate-from-react-loadable.mdx │ ├── prefetching.mdx │ ├── server-side-rendering.mdx │ ├── support.mdx │ ├── suspense.mdx │ └── timeout.mdx └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintignore ================================================ node_modules/ /coverage/ dist/ lib/ build/ /website/.cache/ /website/public/ __testfixtures__/ ================================================ FILE: .eslintrc.json ================================================ { "root": true, "parser": "babel-eslint", "extends": ["airbnb", "prettier"], "env": { "jest": true }, "rules": { "react/jsx-one-expression-per-line": "off", "no-plusplus": "off", "no-param-reassign": "off", "no-nested-ternary": "off", "react/jsx-filename-extension": ["error", { "extensions": [".js"] }], "react/jsx-wrap-multilines": "off", "react/no-unused-state": "off", "react/destructuring-assignment": "off", "react/prop-types": "off", "react/sort-comp": "off", "react/jsx-props-no-spreading": "off", "react/state-in-constructor": "off", "import/extensions": "off", "import/prefer-default-export": "off" } } ================================================ FILE: .github/FUNDING.yml ================================================ github: gregberge open_collective: loadable ================================================ FILE: .github/ISSUE_TEMPLATE/bug.md ================================================ --- name: 🐛 Bug report about: Create a report to help us improve --- ## 🐛 Bug Report A clear and concise description of what the bug is. ## To Reproduce Steps to reproduce the behavior: ## Expected behavior A clear and concise description of what you expected to happen. ## Link to repl or repo (highly encouraged) Please provide a minimal repository on GitHub. Issues without a reproduction link are likely to stall. ## Run `npx envinfo --system --binaries --npmPackages @loadable/component,@loadable/server,@loadable/webpack-plugin,@loadable/babel-plugin --markdown --clipboard` Paste the results here: ```bash ``` ================================================ FILE: .github/ISSUE_TEMPLATE/feature.md ================================================ --- name: 🚀 Feature Proposal about: Submit a proposal for a new feature --- ## 🚀 Feature Proposal A clear and concise description of what the feature is. ## Motivation Please outline the motivation for the proposal. ## Example Please provide an example for how this feature would be used. ## Pitch Why does this feature belong in the Loadable Component ecosystem? ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: 💬 Questions / Help about: If you have questions, please read full readme first --- ## 💬 Questions and Help Loadable Components project is young, but please before asking your question: - Read carefully the README of the project - Search if your answer has already been answered in old issues After you can submit your question and we will be happy to help you! ================================================ FILE: .github/ISSUE_TEMPLATE/regression.md ================================================ --- name: 💥 Regression Report about: Report unexpected behavior that worked in previous versions --- ## 💥 Regression Report A clear and concise description of what the regression is. ## Last working version Worked up to version: Stopped working in version: ## To Reproduce Steps to reproduce the behavior: ## Expected behavior A clear and concise description of what you expected to happen. ## Link to repl or repo (highly encouraged) Please provide a minimal repository on GitHub. Issues without a reproduction link are likely to stall. ## Run `npx envinfo --system --binaries --npmPackages @loadable/component,@loadable/server,@loadable/webpack-plugin,@loadable/babel-plugin --markdown --clipboard` Paste the results here: ```bash ``` ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## 👉 [Please follow one of these issue templates](https://github.com/gregberge/loadable-components/issues/new/choose) 👈 Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Summary ## Test plan ================================================ FILE: .github/SUPPORT.md ================================================ Please read carefully the README before asking questions. ================================================ FILE: .github/opencollective.yml ================================================ collective: loadable tiers: - tiers: '*' labels: ['backer'] message: | Hey :wave:, Thank you so much for supporting us on [Open Collective]() :heart:. We'll give a special attention to this issue. invitation: | Hey :wave:, Thank you for opening an issue. We'll get back to you as soon as we can. Please, consider supporting us on [Open Collective](). We give a special attention to issues opened by backers. If you use Loadable at work, you can also ask your company to sponsor us :heart:. ================================================ FILE: .github/stale.yml ================================================ # Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Label to use when marking an issue as stale staleLabel: wontfix # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. ================================================ FILE: .gitignore ================================================ node_modules/ dist/ lib/ /coverage/ examples/*/yarn.lock ================================================ FILE: .npmignore ================================================ /* !/babel.js !/server.js !/server.d.ts !/dist/**/*.js !/src/**/*.js !/types/index.d.ts !/types/tsconfig.json __fixtures__ *.test.js .size-snapshot.json ================================================ FILE: .npmrc ================================================ registry=https://registry.npmjs.org ================================================ FILE: .nvmrc ================================================ 20 registry=https://registry.npmjs.org ================================================ FILE: .prettierignore ================================================ node_modules/ /coverage/ /dist/ __fixtures__/ CHANGELOG.md package.json lerna.json /website/.cache/ /website/public/ __testfixtures__/ examples/*/public **/dist/ **/lib/ ================================================ FILE: .prettierrc ================================================ { "singleQuote": true, "trailingComma": "all", "semi": false } ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 12 notifications: email: false cache: yarn: true directories: - '.eslintcache' - 'node_modules' git: depth: 5 branches: only: - master - stable script: - yarn ci - yarn --cwd examples/typescript && yarn --cwd examples/typescript build - yarn --cwd examples/webpack/webpack4 && yarn --cwd examples/webpack/webpack4 build - yarn --cwd examples/webpack/webpack5 && yarn --cwd examples/webpack/webpack5 build notifications: email: false ================================================ FILE: BACKERS.md ================================================ # Sponsors & Backers

Support Loadable Components development through donations.

Loadable Components is an MIT-licensed open source project. It is created an maintained by a single person: Greg Bergé. - [Sponsor me on GitHub ❤️](https://github.com/sponsors/gregberge). ================================================ FILE: CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [5.16.7](https://github.com/gregberge/loadable-components/compare/v5.16.6...v5.16.7) (2025-05-18) **Note:** Version bump only for package loadable-components ## [5.16.6](https://github.com/gregberge/loadable-components/compare/v5.16.5...v5.16.6) (2025-05-18) **Note:** Version bump only for package loadable-components ## [5.16.5](https://github.com/smooth-code/loadable-components/compare/v5.16.4...v5.16.5) (2024-04-20) **Note:** Version bump only for package loadable-components ## [5.16.4](https://github.com/smooth-code/loadable-components/compare/v5.16.3...v5.16.4) (2024-04-20) ### Bug Fixes * correct esm configuration for loadable/server, fixes: [#999](https://github.com/smooth-code/loadable-components/issues/999) ([#1004](https://github.com/smooth-code/loadable-components/issues/1004)) ([114cea2](https://github.com/smooth-code/loadable-components/commit/114cea2b61ef644d3b794a9b5f48df69f0f5400b)) ## [5.16.3](https://github.com/smooth-code/loadable-components/compare/v5.16.2...v5.16.3) (2023-12-26) ### Bug Fixes * correct react-is for mjs export; remove isValidComponent check ([#991](https://github.com/smooth-code/loadable-components/issues/991)) ([9d381c3](https://github.com/smooth-code/loadable-components/commit/9d381c35b7fc1f8f9122caac25e8e255871ebab6)) ## [5.16.2](https://github.com/smooth-code/loadable-components/compare/v5.16.1...v5.16.2) (2023-12-15) ### Bug Fixes * add esm exports to package.json and change esm bundle extension to .mjs to allow node.js to properly import esm version of package. ([#989](https://github.com/smooth-code/loadable-components/issues/989)) ([e4a3718](https://github.com/smooth-code/loadable-components/commit/e4a37188b804e6a5bc66f39c23c738006bc0e284)) ## [5.16.1](https://github.com/smooth-code/loadable-components/compare/v5.16.0...v5.16.1) (2023-07-20) ### Bug Fixes * correct babel plugin default signature to allow any source of 'loadable' ([#972](https://github.com/smooth-code/loadable-components/issues/972)) ([19849b6](https://github.com/smooth-code/loadable-components/commit/19849b6ba738fe19c18e61ed3402ee82ba934760)), closes [#971](https://github.com/smooth-code/loadable-components/issues/971) # [5.16.0](https://github.com/smooth-code/loadable-components/compare/v5.15.3...v5.16.0) (2023-07-09) ### Features * Allow additional identifiers to be passed in to the babel plugin ([#966](https://github.com/smooth-code/loadable-components/issues/966)) ([e18e37a](https://github.com/smooth-code/loadable-components/commit/e18e37afd8b30455d3a786b9b0dae5f3bd0d442b)) ## [5.15.3](https://github.com/smooth-code/loadable-components/compare/v5.15.2...v5.15.3) (2023-01-28) ### Bug Fixes * add React 17 and 18 to package dependencies, fixes [#718](https://github.com/smooth-code/loadable-components/issues/718) ([66edc37](https://github.com/smooth-code/loadable-components/commit/66edc37a731a8ec655deffd3ad454fd96e909ba3)) ## [5.15.2](https://github.com/smooth-code/loadable-components/compare/v5.15.1...v5.15.2) (2021-12-12) ### Bug Fixes * Clear correct cache when compiling with Webpack ([#838](https://github.com/smooth-code/loadable-components/issues/838)) ([3b9cb20](https://github.com/smooth-code/loadable-components/commit/3b9cb202a09365e67c08ec18455d82bedf62f4db)) * loadAsync Loadable should copy statics ([#839](https://github.com/smooth-code/loadable-components/issues/839)) ([9ff6693](https://github.com/smooth-code/loadable-components/commit/9ff66939ee6fd622922f71128a30b5d3f43f63b0)) * use stable promises for load/preload/React ([#858](https://github.com/smooth-code/loadable-components/issues/858)) ([45f2d91](https://github.com/smooth-code/loadable-components/commit/45f2d9133c8234fec9cbe36e5a162a61f24e4aae)) ## [5.15.1](https://github.com/smooth-code/loadable-components/compare/v5.15.0...v5.15.1) (2021-08-17) ### Bug Fixes * add cachedAssets to stats options ([#779](https://github.com/smooth-code/loadable-components/issues/779)) ([73b17fd](https://github.com/smooth-code/loadable-components/commit/73b17fd067579b1c5d38eba00e157964e0930a94)), closes [#770](https://github.com/smooth-code/loadable-components/issues/770) * SubResourceIntegrity ([#803](https://github.com/smooth-code/loadable-components/issues/803)) ([9b34195](https://github.com/smooth-code/loadable-components/commit/9b34195627c65372a7c834311c32dfcbd5b7fedd)) # [5.15.0](https://github.com/smooth-code/loadable-components/compare/v5.14.2...v5.15.0) (2021-05-08) ### Bug Fixes * add displayNames to generated components ([#731](https://github.com/smooth-code/loadable-components/issues/731)) ([b640c82](https://github.com/smooth-code/loadable-components/commit/b640c82a742ffbccc423439e2e205d1becdf5491)) ### Features * support multiple Webpack runtimes ([#701](https://github.com/smooth-code/loadable-components/issues/701)) ([d351367](https://github.com/smooth-code/loadable-components/commit/d3513679ed680e46967ca18555116c06e5a4b341)) * webpack plugin doesn't need all chunk info ([#735](https://github.com/smooth-code/loadable-components/issues/735)) ([cea9f24](https://github.com/smooth-code/loadable-components/commit/cea9f249f7550a1154cf88bcfa3812ebb78a500f)) ## [5.14.2](https://github.com/smooth-code/loadable-components/compare/v5.14.1...v5.14.2) (2021-01-31) ### Bug Fixes * ignore css chunk ([#689](https://github.com/smooth-code/loadable-components/issues/689)) ([6926e19](https://github.com/smooth-code/loadable-components/commit/6926e190c80f525467980fffbbded0bf933f27ed)) * remove main asset path query ([#686](https://github.com/smooth-code/loadable-components/issues/686)) ([dde2252](https://github.com/smooth-code/loadable-components/commit/dde2252136a2d7f3ff635f85deff429948130883)) * update hooks for webpack 5 ([#676](https://github.com/smooth-code/loadable-components/issues/676)) ([671ef52](https://github.com/smooth-code/loadable-components/commit/671ef527e7a37c459df616ee74dc92e106e8245e)) ## [5.14.1](https://github.com/smooth-code/loadable-components/compare/v5.14.0...v5.14.1) (2020-10-22) **Note:** Version bump only for package loadable-components # [5.14.0](https://github.com/smooth-code/loadable-components/compare/v5.13.2...v5.14.0) (2020-10-20) ### Bug Fixes * add key to chunks script elements ([#631](https://github.com/smooth-code/loadable-components/issues/631)) ([25b532e](https://github.com/smooth-code/loadable-components/commit/25b532eb53a2841229dbc8a9c91f24112a46b93f)), closes [#628](https://github.com/smooth-code/loadable-components/issues/628) * do not derive cache key if component is static, fixes [#629](https://github.com/smooth-code/loadable-components/issues/629) ([#630](https://github.com/smooth-code/loadable-components/issues/630)) ([b4151d8](https://github.com/smooth-code/loadable-components/commit/b4151d85b3ba0f57e9fab48ec88f5e57e4d0b544)) * treat mjs as script ([575fe2b](https://github.com/smooth-code/loadable-components/commit/575fe2b3f58b18c17416f238780b9bab85110706)) ### Features * make packages webpack 5 compatible ([#638](https://github.com/smooth-code/loadable-components/issues/638)) ([e882e4d](https://github.com/smooth-code/loadable-components/commit/e882e4d812e714066eba19a11dd119193e7a9e01)) ## [5.13.2](https://github.com/smooth-code/loadable-components/compare/v5.13.1...v5.13.2) (2020-09-14) ### Bug Fixes * Fixed lazy usage with Suspense and Error Boundary together ([#521](https://github.com/smooth-code/loadable-components/issues/521)) ([42fbdd0](https://github.com/smooth-code/loadable-components/commit/42fbdd0d552551b18ed0781383bb0073e1cd8640)) * human readable errors ([b86bb82](https://github.com/smooth-code/loadable-components/commit/b86bb82417ad098ed73037159886c4d0481ba34e)) * spread nested required chunks array ([95e6ecb](https://github.com/smooth-code/loadable-components/commit/95e6ecb0dd9be3cf18ded934cca433a660fa3543)) * typo ([bebb828](https://github.com/smooth-code/loadable-components/commit/bebb82811e25475e91f9fadf64fda004b6b649b0)) ## [5.13.1](https://github.com/smooth-code/loadable-components/compare/v5.13.0...v5.13.1) (2020-07-02) ### Bug Fixes * expose used chunkNames from a server. Fixes [#587](https://github.com/smooth-code/loadable-components/issues/587) ([831aec0](https://github.com/smooth-code/loadable-components/commit/831aec03154ab16007db0d78fbf3559583c000fe)) # [5.13.0](https://github.com/smooth-code/loadable-components/compare/v5.12.0...v5.13.0) (2020-06-29) ### Bug Fixes * allow webpack cache is ready only for initial chunks, fixes [#558](https://github.com/smooth-code/loadable-components/issues/558) ([61f8b75](https://github.com/smooth-code/loadable-components/commit/61f8b75b54612368c88807d73abb7dc7add720ad)) * memory leak in module cache management, fixes [#560](https://github.com/smooth-code/loadable-components/issues/560) ([6c11703](https://github.com/smooth-code/loadable-components/commit/6c11703cbc5446fc61d10c47b64e84a00cf899c3)) * use make-dir instead of mkdirp ([#544](https://github.com/smooth-code/loadable-components/issues/544)) ([5a9c33b](https://github.com/smooth-code/loadable-components/commit/5a9c33b222fecb320dc02b643122fbe717aa6fc8)) * **babel-plugin:** add missing peer dependency ([#524](https://github.com/smooth-code/loadable-components/issues/524)) ([03a79b6](https://github.com/smooth-code/loadable-components/commit/03a79b66defc78f150436acd6a9d3e029bb1d470)) ### Features * add `resolveComponent` option ([a47d3d9](https://github.com/smooth-code/loadable-components/commit/a47d3d9021ee6b12c1209bf41069dc133cb1fa7c)) # [5.12.0](https://github.com/gregberge/loadable-components/compare/v5.11.0...v5.12.0) (2020-01-09) ### Bug Fixes * apply loadable transformations before any other, fixes [#466](https://github.com/gregberge/loadable-components/issues/466) ([ac5ba45](https://github.com/gregberge/loadable-components/commit/ac5ba45862bad68b971a969e6e8713874add51a6)) ### Features * add codemods to migrate from react-loadable ([#463](https://github.com/gregberge/loadable-components/issues/463)) ([a82d5ad](https://github.com/gregberge/loadable-components/commit/a82d5ad1e17cd64d3579aa207abfc18346ff0107)) * avoid synchronous loading on client if options.ssr is false ([#346](https://github.com/gregberge/loadable-components/issues/346)) ([338bf55](https://github.com/gregberge/loadable-components/commit/338bf555adc68986b12c8dd4e304875425119ca2)) * loadable-components.com ([e515b0e](https://github.com/gregberge/loadable-components/commit/e515b0e1a73a240fae1ab32f5abd6df23d35efcf)) ### Performance Improvements * avoid calling stats.toJson if possible ([87698de](https://github.com/gregberge/loadable-components/commit/87698de079cb742317a4f6570430ccd5cd526d3e)) # [5.11.0](https://github.com/smooth-code/loadable-components/compare/v5.10.3...v5.11.0) (2019-12-02) ### Bug Fixes * fix isReady problem ([#445](https://github.com/smooth-code/loadable-components/issues/445)) ([3024348](https://github.com/smooth-code/loadable-components/commit/30243482be917e89515d057e2368e7278e34696c)), closes [#400](https://github.com/smooth-code/loadable-components/issues/400) * **server:** use require instead of module.require ([#457](https://github.com/smooth-code/loadable-components/issues/457)) ([064b4f8](https://github.com/smooth-code/loadable-components/commit/064b4f83b291e8a7d73bc44fe4196dc9ddc81fe8)), closes [#455](https://github.com/smooth-code/loadable-components/issues/455) ### Features * add support for SRI (integrity) (with webpack-subresource-integrity) ([#436](https://github.com/smooth-code/loadable-components/issues/436)) ([586ad0a](https://github.com/smooth-code/loadable-components/commit/586ad0af6e172e3a0bffdbe0c8ab682c0d8b0eab)) ## [5.10.3](https://github.com/smooth-code/loadable-components/compare/v5.10.2...v5.10.3) (2019-09-24) ### Bug Fixes * empty cache on each server reload ([#431](https://github.com/smooth-code/loadable-components/issues/431)) ([d4428c6](https://github.com/smooth-code/loadable-components/commit/d4428c6)), closes [#230](https://github.com/smooth-code/loadable-components/issues/230) * support IE 11 without polyfill ([#416](https://github.com/smooth-code/loadable-components/issues/416)) ([80ee809](https://github.com/smooth-code/loadable-components/commit/80ee809)), closes [#397](https://github.com/smooth-code/loadable-components/issues/397) * **babel-plugin:** fix bug when using + concatenation instead of a template literal ([#425](https://github.com/smooth-code/loadable-components/issues/425)) ([d98dd27](https://github.com/smooth-code/loadable-components/commit/d98dd27)) ## [5.10.2](https://github.com/smooth-code/loadable-components/compare/v5.10.1...v5.10.2) (2019-07-15) ### Bug Fixes * use === instead of Object.is ([c88cd82](https://github.com/smooth-code/loadable-components/commit/c88cd82)), closes [#371](https://github.com/smooth-code/loadable-components/issues/371) ### Performance Improvements * use more performant url join impl ([#353](https://github.com/smooth-code/loadable-components/issues/353)) ([c3fbbef](https://github.com/smooth-code/loadable-components/commit/c3fbbef)) ## [5.10.1](https://github.com/smooth-code/loadable-components/compare/v5.10.0...v5.10.1) (2019-05-14) ### Bug Fixes * add @babel/preset-env in rollup config ([#336](https://github.com/smooth-code/loadable-components/issues/336)) ([8b50c94](https://github.com/smooth-code/loadable-components/commit/8b50c94)), closes [#335](https://github.com/smooth-code/loadable-components/issues/335) # [5.10.0](https://github.com/smooth-code/loadable-components/compare/v5.9.0...v5.10.0) (2019-05-13) ### Bug Fixes * fix chunkname mismatch ([#332](https://github.com/smooth-code/loadable-components/issues/332)) ([7ffaa4c](https://github.com/smooth-code/loadable-components/commit/7ffaa4c)), closes [#331](https://github.com/smooth-code/loadable-components/issues/331) ### Features * add `load` method that returns a Promise ([#329](https://github.com/smooth-code/loadable-components/issues/329)) ([a10a9d5](https://github.com/smooth-code/loadable-components/commit/a10a9d5)), closes [#226](https://github.com/smooth-code/loadable-components/issues/226) * support reactive dynamic loadable ([#330](https://github.com/smooth-code/loadable-components/issues/330)) ([d65c5bb](https://github.com/smooth-code/loadable-components/commit/d65c5bb)), closes [#284](https://github.com/smooth-code/loadable-components/issues/284) ### Performance Improvements * optimize rollup config ([c94760b](https://github.com/smooth-code/loadable-components/commit/c94760b)) # [5.9.0](https://github.com/smooth-code/loadable-components/compare/v5.8.0...v5.9.0) (2019-04-23) ### Features * support multiple react apps ([#317](https://github.com/smooth-code/loadable-components/issues/317)) ([dc54050](https://github.com/smooth-code/loadable-components/commit/dc54050)), closes [#311](https://github.com/smooth-code/loadable-components/issues/311) * **server:** authorize custom filesystem ([#318](https://github.com/smooth-code/loadable-components/issues/318)) ([f2a6bbd](https://github.com/smooth-code/loadable-components/commit/f2a6bbd)), closes [#315](https://github.com/smooth-code/loadable-components/issues/315) # [5.8.0](https://github.com/smooth-code/loadable-components/compare/v5.7.2...v5.8.0) (2019-04-10) ### Bug Fixes * **babel-plugin:** Use require.resolve instead of relative path resolution ([#303](https://github.com/smooth-code/loadable-components/issues/303)) ([bad7f1f](https://github.com/smooth-code/loadable-components/commit/bad7f1f)) ### Features * **ChunkExtractor:** support publicPath override ([#292](https://github.com/smooth-code/loadable-components/issues/292)) ([9731e9c](https://github.com/smooth-code/loadable-components/commit/9731e9c)) * **server:** support function in attributes ([#277](https://github.com/smooth-code/loadable-components/issues/277)) ([c172324](https://github.com/smooth-code/loadable-components/commit/c172324)) ### Performance Improvements * **server:** improve lodash imports for serverless bundles ([#298](https://github.com/smooth-code/loadable-components/issues/298)) ([96841f2](https://github.com/smooth-code/loadable-components/commit/96841f2)) ## [5.7.2](https://github.com/smooth-code/loadable-components/compare/v5.7.1...v5.7.2) (2019-03-20) ### Bug Fixes * **babel-plugin:** handle "-" at the end of request ([c0f325b](https://github.com/smooth-code/loadable-components/commit/c0f325b)) ## [5.7.1](https://github.com/smooth-code/loadable-components/compare/v5.7.0...v5.7.1) (2019-03-19) ### Bug Fixes * **babel-plugin:** handle special chars in file names ([#279](https://github.com/smooth-code/loadable-components/issues/279)) ([4da39ff](https://github.com/smooth-code/loadable-components/commit/4da39ff)) * **webpack-plugin:** create output folder with mkdirp ([#273](https://github.com/smooth-code/loadable-components/issues/273)) ([3767f28](https://github.com/smooth-code/loadable-components/commit/3767f28)) # [5.7.0](https://github.com/smooth-code/loadable-components/compare/v5.6.1...v5.7.0) (2019-03-14) ### Bug Fixes * **component:** fix warning message about babel ([#255](https://github.com/smooth-code/loadable-components/issues/255)) ([7cb68a1](https://github.com/smooth-code/loadable-components/commit/7cb68a1)), closes [#253](https://github.com/smooth-code/loadable-components/issues/253) * **server:** fix loading order of assets ([#266](https://github.com/smooth-code/loadable-components/issues/266)) ([4c8ae60](https://github.com/smooth-code/loadable-components/commit/4c8ae60)) ### Features * use inline JSON to enabling CSP without `unsafe-inline` ([05e5500](https://github.com/smooth-code/loadable-components/commit/05e5500)) ### Performance Improvements * **build:** add build target for Node ([#267](https://github.com/smooth-code/loadable-components/issues/267)) ([97ff6ac](https://github.com/smooth-code/loadable-components/commit/97ff6ac)) ## [5.6.1](https://github.com/smooth-code/loadable-components/compare/v5.6.0...v5.6.1) (2019-02-25) ### Bug Fixes * **component:** better ES Modules handling ([#228](https://github.com/smooth-code/loadable-components/issues/228)) ([3628363](https://github.com/smooth-code/loadable-components/commit/3628363)) * **server:** allow query-param cache busting in chunk names ([#229](https://github.com/smooth-code/loadable-components/issues/229)) ([71f7bcd](https://github.com/smooth-code/loadable-components/commit/71f7bcd)) * **server:** use `eval` to prevent webpack warning ([#240](https://github.com/smooth-code/loadable-components/issues/240)) ([948165d](https://github.com/smooth-code/loadable-components/commit/948165d)), closes [#234](https://github.com/smooth-code/loadable-components/issues/234) * **suspense:** fix suspense mode in React v16.8+ ([#251](https://github.com/smooth-code/loadable-components/issues/251)) ([d04e1c9](https://github.com/smooth-code/loadable-components/commit/d04e1c9)) # [5.6.0](https://github.com/smooth-code/loadable-components/compare/v5.5.0...v5.6.0) (2019-02-05) ### Bug Fixes * Add extra props option for links ([#212](https://github.com/smooth-code/loadable-components/issues/212)) ([6714d2a](https://github.com/smooth-code/loadable-components/commit/6714d2a)) * **server:** fix chunkName resolving ([#219](https://github.com/smooth-code/loadable-components/issues/219)) ([ef11e11](https://github.com/smooth-code/loadable-components/commit/ef11e11)) ### Features * **babel-plugin:** transform code annotated with magic comment ([4f832dc](https://github.com/smooth-code/loadable-components/commit/4f832dc)), closes [#192](https://github.com/smooth-code/loadable-components/issues/192) * **component:** add preload method ([#224](https://github.com/smooth-code/loadable-components/issues/224)) ([4a67ace](https://github.com/smooth-code/loadable-components/commit/4a67ace)), closes [#196](https://github.com/smooth-code/loadable-components/issues/196) * **server:** add option to disable SSR ([#223](https://github.com/smooth-code/loadable-components/issues/223)) ([4cab4f9](https://github.com/smooth-code/loadable-components/commit/4cab4f9)), closes [#195](https://github.com/smooth-code/loadable-components/issues/195) # [5.5.0](https://github.com/smooth-code/loadable-components/compare/v5.4.0...v5.5.0) (2019-01-22) ### Features * allow to specify extra attributes in getScriptTags & others ([#210](https://github.com/smooth-code/loadable-components/issues/210)) ([8a3d067](https://github.com/smooth-code/loadable-components/commit/8a3d067)) # [5.4.0](https://github.com/smooth-code/loadable-components/compare/v5.3.0...v5.4.0) (2019-01-17) ### Features * **webpack-plugin:** support custom path in writeToDisk option ([#187](https://github.com/smooth-code/loadable-components/issues/187)) ([4a6f84f](https://github.com/smooth-code/loadable-components/commit/4a6f84f)) # [5.3.0](https://github.com/smooth-code/loadable-components/compare/v5.2.2...v5.3.0) (2019-01-11) ### Features * support inline CSS ([#190](https://github.com/smooth-code/loadable-components/issues/190)) ([2caf676](https://github.com/smooth-code/loadable-components/commit/2caf676)) ## [5.2.2](https://github.com/smooth-code/loadable-components/compare/v5.2.1...v5.2.2) (2018-12-12) ### Bug Fixes * **babel-plugin:** fix chunkName with aggressive code splitting ([e974933](https://github.com/smooth-code/loadable-components/commit/e974933)), closes [#182](https://github.com/smooth-code/loadable-components/issues/182) * ensure that component is mounted before calling `setState` ([#184](https://github.com/smooth-code/loadable-components/issues/184)) ([fe0f47f](https://github.com/smooth-code/loadable-components/commit/fe0f47f)), closes [#180](https://github.com/smooth-code/loadable-components/issues/180) * **server:** fix usage when compiled using webpack ([#185](https://github.com/smooth-code/loadable-components/issues/185)) ([5e28870](https://github.com/smooth-code/loadable-components/commit/5e28870)), closes [#181](https://github.com/smooth-code/loadable-components/issues/181) ## [5.2.1](https://github.com/smooth-code/loadable-components/compare/v5.2.0...v5.2.1) (2018-11-27) ### Bug Fixes * **webpack-plugin:** fix TypeError when set writeToDisk true ([#170](https://github.com/smooth-code/loadable-components/issues/170)) ([2d1fb11](https://github.com/smooth-code/loadable-components/commit/2d1fb11)) * upgrade hoist-non-react-statics@3.2.0 ([122b1ce](https://github.com/smooth-code/loadable-components/commit/122b1ce)) # [5.2.0](https://github.com/smooth-code/loadable-components/compare/v5.1.3...v5.2.0) (2018-11-23) ### Bug Fixes * **server:** fix url join ([#166](https://github.com/smooth-code/loadable-components/issues/166)) ([ba90289](https://github.com/smooth-code/loadable-components/commit/ba90289)) * **server:** support protocol free paths ([#163](https://github.com/smooth-code/loadable-components/issues/163)) ([3b5b115](https://github.com/smooth-code/loadable-components/commit/3b5b115)) ### Features * **webpack-plugin:** add writeToDisk option ([#161](https://github.com/smooth-code/loadable-components/issues/161)) ([6b5ba21](https://github.com/smooth-code/loadable-components/commit/6b5ba21)) ## [5.1.3](https://github.com/smooth-code/loadable-components/compare/v5.1.2...v5.1.3) (2018-11-20) ### Bug Fixes * **server:** exclude http and https from regex ([#155](https://github.com/smooth-code/loadable-components/issues/155)) ([0bb2ad9](https://github.com/smooth-code/loadable-components/commit/0bb2ad9)), closes [#153](https://github.com/smooth-code/loadable-components/issues/153) * **server:** ignore *.hot-update.js ([edcd2c8](https://github.com/smooth-code/loadable-components/commit/edcd2c8)), closes [#148](https://github.com/smooth-code/loadable-components/issues/148) ## [5.1.2](https://github.com/smooth-code/loadable-components/compare/v5.1.1...v5.1.2) (2018-11-13) ### Bug Fixes * fix ref handler in `loadable.lib` ([da05d87](https://github.com/smooth-code/loadable-components/commit/da05d87)) ## [5.1.1](https://github.com/smooth-code/loadable-components/compare/v5.1.0...v5.1.1) (2018-11-13) ### Bug Fixes * **server:** ignore source maps ([9991bbd](https://github.com/smooth-code/loadable-components/commit/9991bbd)), closes [#128](https://github.com/smooth-code/loadable-components/issues/128) # [5.1.0](https://github.com/smooth-code/loadable-components/compare/v5.0.2...v5.1.0) (2018-11-10) ### Features * **server:** add outputPath option in ChunkExtractor ([aac26b3](https://github.com/smooth-code/loadable-components/commit/aac26b3)) ## [5.0.2](https://github.com/smooth-code/loadable-components/compare/v5.0.1...v5.0.2) (2018-11-10) ### Bug Fixes * update peer dependencies ([b0363dc](https://github.com/smooth-code/loadable-components/commit/b0363dc)) # [5.0.0](https://github.com/smooth-code/loadable-components/compare/v4.0.5...v5.0.0) (2018-11-10) ### Bug Fixes * fix loadableReady ([59693bb](https://github.com/smooth-code/loadable-components/commit/59693bb)) ### Features * improve SSR support ([eb1cfe8](https://github.com/smooth-code/loadable-components/commit/eb1cfe8)) ### BREAKING CHANGES * - SSR has been rewritten from scratch, if you use it, please follow the new guide. - Prefetch component and prefetch functions have been removed, please use `webpackPrefetch` instead. ## [4.0.5](https://github.com/smooth-code/loadable-components/compare/v4.0.4...v4.0.5) (2018-11-01) ### Bug Fixes * **server:** fix getScriptElements ([ba424e0](https://github.com/smooth-code/loadable-components/commit/ba424e0)) ## [4.0.4](https://github.com/smooth-code/loadable-components/compare/v4.0.3...v4.0.4) (2018-10-31) ### Bug Fixes * fix peer dependencies ([6816e8c](https://github.com/smooth-code/loadable-components/commit/6816e8c)) ## [4.0.3](https://github.com/smooth-code/loadable-components/compare/v4.0.2...v4.0.3) (2018-10-31) ### Bug Fixes * **server:** disable common chunks optim ([78e7b28](https://github.com/smooth-code/loadable-components/commit/78e7b28)) ## [4.0.2](https://github.com/smooth-code/loadable-components/compare/v4.0.1...v4.0.2) (2018-10-31) ### Bug Fixes * **babel-plugin:** transform into friendly chunk name ([54422cb](https://github.com/smooth-code/loadable-components/commit/54422cb)) * **component:** fix lazy usage ([d711ee0](https://github.com/smooth-code/loadable-components/commit/d711ee0)) ## [4.0.1](https://github.com/smooth-code/loadable-components/compare/v4.0.0...v4.0.1) (2018-10-30) ### Bug Fixes * **component:** do not call ref several times ([8cf3190](https://github.com/smooth-code/loadable-components/commit/8cf3190)) # [4.0.0](https://github.com/smooth-code/loadable-components/compare/v3.0.2...v4.0.0) (2018-10-30) ### Features * add new loadable.lib, change API ([94b2e87](https://github.com/smooth-code/loadable-components/commit/94b2e87)) ### BREAKING CHANGES * - `ErrorComponent` is ignored, please use Error Boundaries to handle errors. - `lazy` is no longer exported - `LoadingComponent` is replaced by `fallback` option - `ref` are now forwarded ## [3.0.2](https://github.com/smooth-code/loadable-components/compare/v3.0.1...v3.0.2) (2018-10-30) ### Bug Fixes * **component:** fix loadComponent (typo) ([a410cb2](https://github.com/smooth-code/loadable-components/commit/a410cb2)) ## [3.0.1](https://github.com/smooth-code/loadable-components/compare/v3.0.0...v3.0.1) (2018-10-30) ### Bug Fixes * **component:** fix loadComponents ([bd2220c](https://github.com/smooth-code/loadable-components/commit/bd2220c)) # [3.0.0](https://github.com/smooth-code/loadable-components/compare/v2.2.3...v3.0.0) (2018-10-29) ### Bug Fixes * **typescript:** restore types ([#113](https://github.com/smooth-code/loadable-components/issues/113)) ([240bb8f](https://github.com/smooth-code/loadable-components/commit/240bb8f)) ### Features * welcome loadable ([4dffad7](https://github.com/smooth-code/loadable-components/commit/4dffad7)) ### BREAKING CHANGES * API has completely changed, see documentation. # Change Log All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ## [2.2.3](https://github.com/smooth-code/loadable-components/compare/v2.2.2...v2.2.3) (2018-08-16) ### Bug Fixes * fix type definitions (#95) ([8402c19](https://github.com/smooth-code/loadable-components/commit/8402c19)), closes [#95](https://github.com/smooth-code/loadable-components/issues/95) * support non-ES modules (#104) ([2a82314](https://github.com/smooth-code/loadable-components/commit/2a82314)) ## [2.2.2](https://github.com/smooth-code/loadable-components/compare/v2.2.1...v2.2.2) (2018-05-25) ### Bug Fixes * fix error handling in loadComponents (#87) ([d32c74c](https://github.com/smooth-code/loadable-components/commit/d32c74c)), closes [#87](https://github.com/smooth-code/loadable-components/issues/87) ## [2.2.1](https://github.com/smooth-code/loadable-components/compare/v2.2.0...v2.2.1) (2018-05-23) # [2.2.0](https://github.com/smooth-code/loadable-components/compare/v2.1.0...v2.2.0) (2018-05-23) ### Bug Fixes * fix SSR with HMR #85 ([20138e1](https://github.com/smooth-code/loadable-components/commit/20138e1)), closes [#85](https://github.com/smooth-code/loadable-components/issues/85) ### Features * experimental suspense 🤩 ([57ce712](https://github.com/smooth-code/loadable-components/commit/57ce712)) # [2.1.0](https://github.com/smooth-code/loadable-components/compare/v2.0.1...v2.1.0) (2018-05-13) ### Features * add TypeScript definitions (#80) ([db19796](https://github.com/smooth-code/loadable-components/commit/db19796)) ## [2.0.1](https://github.com/smooth-code/loadable-components/compare/v2.0.0...v2.0.1) (2018-05-12) ### Bug Fixes * fix module resolving ([10318b0](https://github.com/smooth-code/loadable-components/commit/10318b0)), closes [#59](https://github.com/smooth-code/loadable-components/issues/59) # [2.0.0](https://github.com/smooth-code/loadable-components/compare/v1.4.0...v2.0.0) (2018-05-10) ### Bug Fixes * do not propagate componentId ([fff1248](https://github.com/smooth-code/loadable-components/commit/fff1248)) ### Code Refactoring * remove HMR relative code ([ef0817c](https://github.com/smooth-code/loadable-components/commit/ef0817c)) ### BREAKING CHANGES * `setConfig` is no longer available. # [1.4.0](https://github.com/smooth-code/loadable-components/compare/v1.3.0...v1.4.0) (2018-04-18) ### Bug Fixes * set correct loading state if component is already loaded. (#64) ([9b0cae2](https://github.com/smooth-code/loadable-components/commit/9b0cae2)) ### Features * support React.createContext API (#65) ([289ad67](https://github.com/smooth-code/loadable-components/commit/289ad67)) # [1.3.0](https://github.com/smooth-code/loadable-components/compare/v1.2.0...v1.3.0) (2018-04-06) ### Bug Fixes * circular structure in error object (#60) ([96333ca](https://github.com/smooth-code/loadable-components/commit/96333ca)) * React 16.3 compatibility ([abd7963](https://github.com/smooth-code/loadable-components/commit/abd7963)), closes [#57](https://github.com/smooth-code/loadable-components/issues/57) ### Features * attach static properties on load ([d383fab](https://github.com/smooth-code/loadable-components/commit/d383fab)), closes [#58](https://github.com/smooth-code/loadable-components/issues/58) # [1.2.0](https://github.com/smooth-code/loadable-components/compare/v1.1.1...v1.2.0) (2018-03-25) ### Features * add Hot Reload support ([c79085e](https://github.com/smooth-code/loadable-components/commit/c79085e)) ## [1.1.1](https://github.com/smooth-code/loadable-components/compare/v1.1.0...v1.1.1) (2018-02-06) ### Bug Fixes * **snapshot:** fix snap usage ([3445bea](https://github.com/smooth-code/loadable-components/commit/3445bea)), closes [#40](https://github.com/smooth-code/loadable-components/issues/40) # [1.1.0](https://github.com/smooth-code/loadable-components/compare/v1.0.2...v1.1.0) (2018-02-04) ### Features * ship a single js file ([99e08c0](https://github.com/smooth-code/loadable-components/commit/99e08c0)) ## [1.0.2](https://github.com/smooth-code/loadable-components/compare/v1.0.1...v1.0.2) (2018-02-04) ### Bug Fixes * state could have no children ([a47c410](https://github.com/smooth-code/loadable-components/commit/a47c410)), closes [#36](https://github.com/smooth-code/loadable-components/issues/36) ## [1.0.1](https://github.com/smooth-code/loadable-components/compare/v1.0.0...v1.0.1) (2018-02-03) ### Bug Fixes * fix loadComponents without valid state ([35f81a6](https://github.com/smooth-code/loadable-components/commit/35f81a6)), closes [#34](https://github.com/smooth-code/loadable-components/issues/34) # [1.0.0](https://github.com/smooth-code/loadable-components/compare/v0.4.0...v1.0.0) (2018-02-02) ### Features * stable version 1 ([601bd34](https://github.com/smooth-code/loadable-components/commit/601bd34)) ### BREAKING CHANGES * loadable-components/babel is now required if you do server side rendering. * ErrorComponent now receive `ownProps` instead of `props`. ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project author at hey@gregberge.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute Loadable Components is a small project, it is widely used but has not a lot of contributors. We're still working out the kinks to make contributing to this project as easy and transparent as possible, but we're not quite there yet. Hopefully this document makes the process for contributing clear and answers some questions that you may have. ## [Code of Conduct](https://github.com/gregberge/loadable-components/blob/master/CODE_OF_CONDUCT.md) We expect project participants to adhere to our Code of Conduct. Please read [the full text](https://github.com/gregberge/loadable-components/blob/master/CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated. ## Open Development All work on Loadable Components happens directly on [GitHub](/). Both core team members and external contributors send pull requests which go through the same review process. ### Workflow and Pull Requests _Before_ submitting a pull request, please make sure the following is done… 1. Fork the repo and create your branch from `master`. A guide on how to fork a repository: https://help.github.com/articles/fork-a-repo/ Open terminal (e.g. Terminal, iTerm, Git Bash or Git Shell) and type: ```sh-session $ git clone https://github.com//loadable-components $ cd loadable-components $ git checkout -b my_branch ``` Note: Replace `` with your GitHub username 2. Loadable Components uses [Yarn](https://code.fb.com/web/yarn-a-new-package-manager-for-javascript/) for running development scripts. If you haven't already done so, please [install yarn](https://yarnpkg.com/en/docs/install). 3. Run `yarn install`. On Windows: To install [Yarn](https://yarnpkg.com/en/docs/install#windows-tab) on Windows you may need to download either node.js or Chocolatey
```sh yarn install ``` To check your version of Yarn and ensure it's installed you can type: ```sh yarn --version ``` 4. Run `yarn build` to bootstrap packages. ```sh yarn build ``` 5. If you've added code that should be tested, add tests. You can use watch mode that continuously transforms changed files to make your life easier. ```sh # in the background yarn run dev ``` 6. If you've changed APIs, update the documentation. 7. Ensure the linting is good via `yarn lint`. ```sh-session $ yarn lint ``` 8. Ensure the test suite passes via `yarn test`. ```sh-session $ yarn test:prepare # build example and generate fixtures before running tests $ yarn test ``` #### Testing with your own project You can use `yarn run release-to-git` to create releases as tags on github. This requires that: - Your git remote (where you want to publish the tags) is `origin` - Your commit messages follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. For example: `feat: add timeout option`. ## Bugs ### Where to Find Known Issues We will be using GitHub Issues for our public bugs. We will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new issue, try to make sure your problem doesn't already exist. ### Reporting New Issues The best way to get your bug fixed is to provide a reduced test case. Please provide a public repository with a runnable example. ## Code Conventions Please follow the `.prettierrc` in the project. ## License By contributing to Loadable Components, you agree that your contributions will be licensed under its MIT license. ================================================ FILE: LICENSE ================================================ Copyright 2019 Greg Bergé Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

loadable-components

React code splitting made easy. Reduce your bundle size without stress ✂️✨.

[![License](https://img.shields.io/npm/l/@loadable/component.svg)](https://github.com/gregberge/loadable-components/blob/master/LICENSE) [![npm package](https://img.shields.io/npm/v/@loadable/component/latest.svg)](https://www.npmjs.com/package/@loadable/component) [![npm downloads](https://img.shields.io/npm/dm/@loadable/component.svg)](https://www.npmjs.com/package/@loadable/component) [![Build Status](https://img.shields.io/travis/gregberge/loadable-components.svg)](https://travis-ci.org/gregberge/loadable-components) ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) [![Dependencies](https://img.shields.io/david/gregberge/loadable-components.svg?path=packages%2Fcomponent)](https://david-dm.org/gregberge/loadable-components?path=packages/component) [![DevDependencies](https://img.shields.io/david/dev/gregberge/loadable-components.svg)](https://david-dm.org/gregberge/loadable-components?type=dev) [![Small size](https://img.badgesize.io/https://unpkg.com/@loadable/component/dist/loadable.min.js?compression=gzip)](https://unpkg.com/@loadable/component/dist/loadable.min.js) ```bash npm install @loadable/component ``` ## [Docs](https://loadable-components.com) **See the documentation at [loadable-components.com](https://loadable-components.com)** for more information about using Loadable Components! Quicklinks to some of the most-visited pages: - [**Getting started**](https://loadable-components.com/docs/getting-started/) - [Comparison with React.lazy](https://loadable-components.com/docs/loadable-vs-react-lazy/) - [Server Side Rendering](https://loadable-components.com/docs/server-side-rendering/) ## Example ```js import loadable from '@loadable/component' const OtherComponent = loadable(() => import('./OtherComponent')) function MyComponent() { return (
) } ``` ## Supporting Loadable Components Loadable Components is an MIT-licensed open source project. It's an independent project with ongoing development made possible thanks to the support of these awesome [backers](/BACKERS.md). If you'd like to join them, please consider: - [Sponsor me on GitHub ❤️](https://github.com/sponsors/gregberge). ## License Licensed under the MIT License, Copyright © 2017-present Greg Bergé. See [LICENSE](./LICENSE) for more information. ================================================ FILE: babel.config.js ================================================ function getTargets() { if (process.env.BUILD_TARGET === 'node') { return { node: '8' } } return undefined } function getModules() { if (process.env.MODULE_TARGET === 'cjs') { return 'cjs' } if (process.env.MODULE_TARGET === 'esm') { return false } return 'auto' } module.exports = { presets: [ ['@babel/preset-react', { useBuiltIns: true }], [ '@babel/preset-env', { loose: true, targets: getTargets(), modules: getModules() }, ], ], plugins: ['@babel/plugin-proposal-class-properties'], } ================================================ FILE: examples/client-side/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off" } } ================================================ FILE: examples/client-side/README.md ================================================ # Get the client-side example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/client-side ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run ```bash yarn dev # or yarn start ``` ================================================ FILE: examples/client-side/babel.config.js ================================================ module.exports = { presets: ['@babel/preset-react'], plugins: ['@babel/plugin-syntax-dynamic-import'], } ================================================ FILE: examples/client-side/package.json ================================================ { "private": true, "scripts": { "start": "webpack-dev-server", "dev": "webpack-dev-server" }, "devDependencies": { "@babel/core": "^7.6.4", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/preset-react": "^7.6.3", "babel-loader": "^8.0.4", "html-webpack-plugin": "^3.2.0", "webpack": "^4.30.0", "webpack-cli": "^3.3.2", "webpack-dev-server": "^3.3.1" }, "dependencies": { "@loadable/component": "^5.10.3", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/client-side/src/A.js ================================================ export default () => 'A' ================================================ FILE: examples/client-side/src/B.js ================================================ export default () => 'B' ================================================ FILE: examples/client-side/src/Hello.js ================================================ export default () => 'Hello' ================================================ FILE: examples/client-side/src/index.js ================================================ import React, { useState } from 'react' import { render } from 'react-dom' import loadable from '@loadable/component' const Hello = loadable(() => import('./Hello')) const Dynamic = loadable(p => import(`./${p.name}`), { cacheKey: p => p.name, }) const Moment = loadable.lib(() => import('moment')) function App() { const [name, setName] = useState(null) return (
{name && } {({ default: moment }) => moment().format('HH:mm')}
) } const root = document.createElement('div') document.body.append(root) render(, root) ================================================ FILE: examples/client-side/webpack.config.js ================================================ const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { mode: 'development', module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: 'babel-loader', }, ], }, plugins: [new HtmlWebpackPlugin()], } ================================================ FILE: examples/razzle/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/razzle/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/razzle/README.md ================================================ # Get the razzle example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/razzle ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run locally or build and serve ```bash yarn dev # or yarn build yarn start:prod ``` ================================================ FILE: examples/razzle/package.json ================================================ { "private": true, "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "@babel/runtime": "^7.1.5", "@loadable/component": "^5.10.2", "@loadable/server": "^5.10.2", "@reach/router": "^1.2.1", "babel-jest": "^24.8.0", "common-tags": "^1.8.0", "express": "^4.16.2", "normalize.css": "^8.0.1", "razzle": "^3.0.0-alpha.0", "react": "^16.0.0", "react-dom": "^16.0.0" }, "devDependencies": { "@babel/template": "^7.4.4", "@loadable/babel-plugin": "^5.10.0", "@loadable/webpack-plugin": "^5.7.1", "check-prop-types": "^1.1.2" } } ================================================ FILE: examples/razzle/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/razzle/razzle.config.js ================================================ /* eslint-disable prefer-object-spread */ const path = require('path') const LoadableWebpackPlugin = require('@loadable/webpack-plugin') const LoadableBabelPlugin = require('@loadable/babel-plugin') const babelPresetRazzle = require('razzle/babel') module.exports = { modify: (config, { dev, target }) => { const appConfig = Object.assign({}, config) if (target === 'web') { const filename = path.resolve(__dirname, 'build') appConfig.plugins = [ ...appConfig.plugins, new LoadableWebpackPlugin({ outputAsset: false, writeToDisk: { filename }, }), ] appConfig.output.filename = dev ? 'static/js/[name].js' : 'static/js/[name].[chunkhash:8].js' appConfig.node = { fs: 'empty' } // fix "Cannot find module 'fs'" problem. appConfig.optimization = Object.assign({}, appConfig.optimization, { runtimeChunk: true, splitChunks: { chunks: 'all', name: dev, }, }) } return appConfig }, modifyBabelOptions: () => ({ babelrc: false, presets: [babelPresetRazzle], plugins: [LoadableBabelPlugin], }), } ================================================ FILE: examples/razzle/src/About/index.js ================================================ import React from 'react' const About = () =>
About page
export default About ================================================ FILE: examples/razzle/src/App.css ================================================ body { margin: 0; padding: 0; font-family: sans-serif; } ================================================ FILE: examples/razzle/src/App.js ================================================ import React from 'react' import { Router, Link } from '@reach/router' import loadable from '@loadable/component' import './App.css' const NotFound = loadable(() => import('./NotFound')) const Home = loadable(() => import('./Home')) const About = loadable(() => import('./About')) const Contact = loadable(() => import('./Contact')) const App = () => ( <> Home About Contact loading...} /> loading...} /> loading...} /> loading...} /> ) export default App ================================================ FILE: examples/razzle/src/Contact/index.js ================================================ import React from 'react' const Contact = () =>
Contact page
export default Contact ================================================ FILE: examples/razzle/src/Home/Home.css ================================================ .Home { text-align: center; } .Home-logo { animation: Home-logo-spin infinite 20s linear; height: 80px; } .Home-header { background-color: #222; height: 150px; padding: 20px; color: white; } .Home-intro { font-size: large; } .Home-resources { list-style: none; } .Home-resources > li { display: inline-block; padding: 1rem; } @keyframes Home-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/razzle/src/Home/Intro.js ================================================ /* eslint-disable react/jsx-one-expression-per-line */ import React from 'react' const Intro = () => (

To get started, edit src/App.js or src/Home.js and save to reload.

) export default Intro ================================================ FILE: examples/razzle/src/Home/Logo.js ================================================ import React from 'react' import logo from './react.svg' const Logo = () => logo export default Logo ================================================ FILE: examples/razzle/src/Home/Welcome.js ================================================ import React from 'react' const Welcome = () =>

Welcome to Razzle

export default Welcome ================================================ FILE: examples/razzle/src/Home/index.js ================================================ import React from 'react' import loadable from '@loadable/component' import './Home.css' const Intro = loadable(() => import('./Intro')) const Welcome = loadable(() => import('./Welcome')) const Logo = loadable(() => import('./Logo')) const Home = () => ( ) export default Home ================================================ FILE: examples/razzle/src/NotFound/index.js ================================================ import React from 'react' const NotFound = () =>
Page could not be found
export default NotFound ================================================ FILE: examples/razzle/src/client.js ================================================ import 'normalize.css' import React from 'react' import { hydrate } from 'react-dom' import { loadableReady } from '@loadable/component' import App from './App' const root = document.getElementById('root') loadableReady(() => { hydrate(, root) }) if (module.hot) { module.hot.accept() } ================================================ FILE: examples/razzle/src/index.js ================================================ /* eslint-disable no-console, global-require */ import http from 'http' let app = require('./server').default const server = http.createServer(app) let currentApp = app server.listen(process.env.PORT || 3000, error => { if (error) { console.log(error) } console.log('🚀 started') }) if (module.hot) { console.log('✅ Server-side HMR Enabled!') module.hot.accept('./server', () => { console.log('🔁 HMR Reloading `./server`...') try { app = require('./server').default server.removeListener('request', currentApp) server.on('request', app) currentApp = app } catch (error) { console.error(error) } }) } ================================================ FILE: examples/razzle/src/server.js ================================================ import path from 'path' import React from 'react' import express from 'express' import { html as htmlTemplate, oneLineTrim } from 'common-tags' import { renderToString } from 'react-dom/server' import { ServerLocation } from '@reach/router' import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server' import App from './App' const server = express() server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const extractor = new ChunkExtractor({ statsFile: path.resolve('build/loadable-stats.json'), entrypoints: ['client'], }) const html = renderToString( , ) res.status(200).send( oneLineTrim(htmlTemplate` Welcome to Razzle ${extractor.getLinkTags()} ${extractor.getStyleTags()}
${html}
${extractor.getScriptTags()} `), ) }) export default server ================================================ FILE: examples/server-side-rendering/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/server-side-rendering/.gitignore ================================================ public/dist ================================================ FILE: examples/server-side-rendering/README.md ================================================ # Get the SSR example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. Install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 3. Install libary dependencies and build library ```bash yarn yarn build ``` 4. Move into example directory ```bash cd ./loadable-components/examples/server-side-rendering ``` 5. Install project dependencies ```bash yarn ``` 5. Run locally or build and serve ```bash yarn dev # Or yarn build yarn start ``` 🍻 ================================================ FILE: examples/server-side-rendering/babel.config.js ================================================ function isWebTarget(caller) { return Boolean(caller && caller.target === 'web') } function isWebpack(caller) { return Boolean(caller && caller.name === 'babel-loader') } module.exports = api => { const web = api.caller(isWebTarget) const webpack = api.caller(isWebpack) return { presets: [ '@babel/preset-react', [ '@babel/preset-env', { useBuiltIns: web ? 'entry' : undefined, corejs: web ? 'core-js@3' : false, targets: !web ? { node: 'current' } : undefined, modules: webpack ? false : 'commonjs', }, ], ], plugins: ['@babel/plugin-syntax-dynamic-import', '@loadable/babel-plugin'], } } ================================================ FILE: examples/server-side-rendering/nodemon.json ================================================ { "ignore": ["client", "public"], "execMap": { "js": "babel-node" } } ================================================ FILE: examples/server-side-rendering/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon src/server/main.js", "build": "rm -Rf ./public && NODE_ENV=production yarn build:webpack && yarn build:lib", "build:webpack": "webpack", "build:lib": "babel -d lib src", "start": "NODE_ENV=production node lib/server/main.js", "link:all": "yarn link @loadable/babel-plugin && yarn link @loadable/server && yarn link @loadable/component" }, "devDependencies": { "@babel/cli": "^7.4.4", "@babel/core": "^7.6.2", "@babel/node": "^7.0.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "@loadable/babel-plugin": "file:./../../packages/babel-plugin", "@loadable/component": "file:./../../packages/component", "@loadable/server": "file:./../../packages/server", "@loadable/webpack-plugin": "file:./../../packages/webpack-plugin", "babel-loader": "^8.0.6", "css-loader": "^2.1.1", "mini-css-extract-plugin": "^0.6.0", "nodemon": "^1.19.0", "webpack": "^4.31.0", "webpack-cli": "^3.3.2", "webpack-dev-middleware": "^3.6.2", "webpack-node-externals": "^1.7.2" }, "dependencies": { "core-js": "^3.0.1", "express": "^4.16.4", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/server-side-rendering/src/client/App.js ================================================ import React from 'react' // eslint-disable-next-line import/no-extraneous-dependencies import loadable from '@loadable/component' import './main.css' const A = loadable(() => import('./letters/A')) const B = loadable(() => import('./letters/B')) const C = loadable(() => import(/* webpackPreload: true */ './letters/C')) const D = loadable(() => import(/* webpackPrefetch: true */ './letters/D')) const E = loadable(() => import('./letters/E?param'), { ssr: false }) const X = loadable(props => import(`./letters/${props.letter}`)) const Sub = loadable(props => import(`./letters/${props.letter}/file`)) const RootSub = loadable(props => import(`./${props.letter}/file`)) // Load the 'G' component twice: once in SSR and once fully client-side const GClient = loadable(() => import('./letters/G'), { ssr: false, fallback: ssr: false - Loading..., }) const GServer = loadable(() => import('./letters/G'), { ssr: true, fallback: ssr: true - Loading..., }) // We keep some references to prevent uglify remove A.C = C A.D = D const Moment = loadable.lib(() => import('moment'), { resolveComponent: moment => moment.default || moment, }) const App = () => ( ) export default App ================================================ FILE: examples/server-side-rendering/src/client/Y/file.js ================================================ export default () => 'Y' ================================================ FILE: examples/server-side-rendering/src/client/letters/A.css ================================================ /* A CSS */ body { background: pink; } ================================================ FILE: examples/server-side-rendering/src/client/letters/A.js ================================================ // We simulate that "moment" is called in "A" and "B" import moment from 'moment' import './A.css' const A = () => 'A' // We keep a reference to prevent uglify remove A.moment = moment export default A ================================================ FILE: examples/server-side-rendering/src/client/letters/B.js ================================================ // We simulate that "moment" is called in "A" and "B" import moment from 'moment' const B = () => 'B' // We keep a reference to prevent uglify remove B.moment = moment export default B ================================================ FILE: examples/server-side-rendering/src/client/letters/C.js ================================================ export default () => 'C' ================================================ FILE: examples/server-side-rendering/src/client/letters/D.js ================================================ export default () => 'D' ================================================ FILE: examples/server-side-rendering/src/client/letters/E.js ================================================ export default () => 'E' ================================================ FILE: examples/server-side-rendering/src/client/letters/F.js ================================================ export default () => 'F' ================================================ FILE: examples/server-side-rendering/src/client/letters/G.js ================================================ import React from 'react' const G = ({ prefix }) => {prefix} - G export default G ================================================ FILE: examples/server-side-rendering/src/client/letters/Z/file.js ================================================ export default () => 'Z' ================================================ FILE: examples/server-side-rendering/src/client/main-node.js ================================================ export { default } from './App' export const hello = 'hello' ================================================ FILE: examples/server-side-rendering/src/client/main-web.js ================================================ import 'core-js' import React from 'react' import { hydrate } from 'react-dom' // eslint-disable-next-line import/no-extraneous-dependencies import { loadableReady } from '@loadable/component' import App from './App' loadableReady(() => { const root = document.getElementById('main') hydrate(, root) }) ================================================ FILE: examples/server-side-rendering/src/client/main.css ================================================ /* Main CSS */ h1 { color: cyan; } ================================================ FILE: examples/server-side-rendering/src/server/main.js ================================================ import path from 'path' import express from 'express' import React from 'react' import { renderToString } from 'react-dom/server' import { ChunkExtractor } from '@loadable/server' const app = express() app.use(express.static(path.join(__dirname, '../../public'))) if (process.env.NODE_ENV !== 'production') { /* eslint-disable global-require, import/no-extraneous-dependencies */ const { default: webpackConfig } = require('../../webpack.config.babel') const webpackDevMiddleware = require('webpack-dev-middleware') const webpack = require('webpack') /* eslint-enable global-require, import/no-extraneous-dependencies */ const compiler = webpack(webpackConfig) app.use( webpackDevMiddleware(compiler, { logLevel: 'silent', publicPath: '/dist/web', writeToDisk(filePath) { return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath) }, }), ) } const nodeStats = path.resolve( __dirname, '../../public/dist/node/loadable-stats.json', ) const webStats = path.resolve( __dirname, '../../public/dist/web/loadable-stats.json', ) app.get('*', (req, res) => { const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats }) const { default: App } = nodeExtractor.requireEntrypoint() const webExtractor = new ChunkExtractor({ statsFile: webStats }) const jsx = webExtractor.collectChunks() const html = renderToString(jsx) res.set('content-type', 'text/html') res.send(` ${webExtractor.getLinkTags()} ${webExtractor.getStyleTags()}
${html}
${webExtractor.getScriptTags()} `) }) // eslint-disable-next-line no-console app.listen(9000, () => console.log('Server started http://localhost:9000')) ================================================ FILE: examples/server-side-rendering/webpack.config.babel.js ================================================ import path from 'path' import nodeExternals from 'webpack-node-externals' import LoadablePlugin from '@loadable/webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' const DIST_PATH = path.resolve(__dirname, 'public/dist') const production = process.env.NODE_ENV === 'production' const development = !process.env.NODE_ENV || process.env.NODE_ENV === 'development' const getConfig = target => ({ name: target, mode: development ? 'development' : 'production', target, entry: `./src/client/main-${target}.js`, module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { caller: { target }, }, }, }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, 'css-loader', ], }, ], }, optimization: { moduleIds: 'named', chunkIds: 'named', }, externals: target === 'node' ? ['@loadable/component', nodeExternals()] : undefined, output: { path: path.join(DIST_PATH, target), // filename: production ? '[name]-bundle-[chunkhash:8].js' : '[name].js', filename: production ? '[name].js' : '[name].js', publicPath: `/dist/${target}/`, libraryTarget: target === 'node' ? 'commonjs2' : undefined, }, plugins: [new LoadablePlugin(), new MiniCssExtractPlugin()], }) export default [getConfig('web'), getConfig('node')] ================================================ FILE: examples/server-side-rendering-async-node/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/server-side-rendering-async-node/.gitignore ================================================ public/dist ================================================ FILE: examples/server-side-rendering-async-node/README.md ================================================ > WORK IN PROGRESS # Get the SSR example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/server-side-rendering-async-node ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run locally or build and serve ```bash yarn dev # Or yarn build yarn start ``` 🍻 ================================================ FILE: examples/server-side-rendering-async-node/babel.config.js ================================================ function isWebTarget(caller) { return Boolean(caller && caller.target === 'web') } function isWebpack(caller) { return Boolean(caller && caller.name === 'babel-loader') } module.exports = api => { const web = api.caller(isWebTarget) const webpack = api.caller(isWebpack) return { presets: [ '@babel/preset-react', [ '@babel/preset-env', { useBuiltIns: web ? 'entry' : undefined, corejs: web ? 'core-js@3' : false, targets: !web ? { node: 'current' } : undefined, modules: webpack ? false : 'commonjs', }, ], ], plugins: ['@babel/plugin-syntax-dynamic-import', '@loadable/babel-plugin'], } } ================================================ FILE: examples/server-side-rendering-async-node/nodemon.json ================================================ { "ignore": ["client", "public"], "execMap": { "js": "babel-node" } } ================================================ FILE: examples/server-side-rendering-async-node/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon src/server/main.js", "build": "NODE_ENV=production yarn build:webpack && yarn build:lib", "build:webpack": "webpack", "build:lib": "babel -d lib src", "start": "NODE_ENV=production node lib/server/main.js" }, "devDependencies": { "@babel/cli": "^7.4.4", "@babel/core": "^7.6.2", "@babel/node": "^7.0.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "@loadable/babel-plugin": "^5.10.3", "@loadable/component": "^5.10.3", "@loadable/server": "^5.10.3", "@loadable/webpack-plugin": "^5.7.1", "babel-loader": "^8.0.6", "css-loader": "^2.1.1", "mini-css-extract-plugin": "^0.6.0", "nodemon": "^1.19.0", "webpack": "^5.0.0-beta.16", "webpack-cli": "^3.3.2", "webpack-dev-middleware": "^3.6.2", "webpack-node-externals": "^1.7.2" }, "dependencies": { "core-js": "^3.0.1", "express": "^4.16.4", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/server-side-rendering-async-node/src/client/App.js ================================================ import React from 'react' // eslint-disable-next-line import/no-extraneous-dependencies import loadable from '@loadable/component' import './main.css' const A = loadable(() => import('./letters/A')) const B = loadable(() => import('./letters/B')) const C = loadable(() => import(/* webpackPreload: true */ './letters/C')) const D = loadable(() => import(/* webpackPrefetch: true */ './letters/D')) const E = loadable(() => import('./letters/E'), { ssr: false }) const X = loadable(props => import(`./letters/${props.letter}`)) const Sub = loadable(props => import(`./letters/${props.letter}/file`)) const RootSub = loadable(props => import(`./${props.letter}/file`)) // Load the 'G' component twice: once in SSR and once fully client-side const GClient = loadable(() => import('./letters/G'), { ssr: false, fallback: ssr: false - Loading..., }) const GServer = loadable(() => import('./letters/G'), { ssr: true, fallback: ssr: true - Loading..., }) // We keep some references to prevent uglify remove A.C = C A.D = D const Moment = loadable.lib(() => import('moment')) const App = () => (
) export default App ================================================ FILE: examples/server-side-rendering-async-node/src/client/Y/file.js ================================================ export default () => 'Y' ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/A.css ================================================ /* A CSS */ ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/A.js ================================================ // We simulate that "moment" is called in "A" and "B" import moment from 'moment' import './A.css' const A = () => 'A' // We keep a reference to prevent uglify remove A.moment = moment export default A ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/B.js ================================================ // We simulate that "moment" is called in "A" and "B" import moment from 'moment' const B = () => 'B' // We keep a reference to prevent uglify remove B.moment = moment export default B ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/C.js ================================================ export default () => 'C' ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/D.js ================================================ export default () => 'D' ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/E.js ================================================ export default () => 'E' ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/F.js ================================================ export default () => 'F' ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/G.js ================================================ import React from 'react' const G = ({ prefix }) => {prefix} - G export default G ================================================ FILE: examples/server-side-rendering-async-node/src/client/letters/Z/file.js ================================================ export default () => 'Z' ================================================ FILE: examples/server-side-rendering-async-node/src/client/main-async-node.js ================================================ export { default } from './App' ================================================ FILE: examples/server-side-rendering-async-node/src/client/main-web.js ================================================ import 'core-js' import React from 'react' import { hydrate } from 'react-dom' // eslint-disable-next-line import/no-extraneous-dependencies import { loadableReady } from '@loadable/component' import App from './App' loadableReady(() => { const root = document.getElementById('main') hydrate(, root) }) ================================================ FILE: examples/server-side-rendering-async-node/src/client/main.css ================================================ /* Main CSS */ ================================================ FILE: examples/server-side-rendering-async-node/src/server/main.js ================================================ import path from 'path' import express from 'express' import React from 'react' import { renderToString } from 'react-dom/server' import { ChunkExtractor } from '@loadable/server' const app = express() app.use(express.static(path.join(__dirname, '../../public'))) if (process.env.NODE_ENV !== 'production') { /* eslint-disable global-require, import/no-extraneous-dependencies */ const { default: webpackConfig } = require('../../webpack.config.babel') const webpackDevMiddleware = require('webpack-dev-middleware') const webpack = require('webpack') /* eslint-enable global-require, import/no-extraneous-dependencies */ const compiler = webpack(webpackConfig) app.use( webpackDevMiddleware(compiler, { logLevel: 'silent', publicPath: '/dist/web', writeToDisk(filePath) { return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath) }, }), ) } const nodeStats = path.resolve( __dirname, '../../public/dist/async-node/loadable-stats.json', ) const webStats = path.resolve( __dirname, '../../public/dist/web/loadable-stats.json', ) app.get('*', (req, res) => { const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats }) const { default: App } = nodeExtractor.requireEntrypoint() const webExtractor = new ChunkExtractor({ statsFile: webStats }) const jsx = webExtractor.collectChunks() const html = renderToString(jsx) res.set('content-type', 'text/html') res.send(` ${webExtractor.getLinkTags()} ${webExtractor.getStyleTags()}
${html}
${webExtractor.getScriptTags()} `) }) // eslint-disable-next-line no-console app.listen(9000, () => console.log('Server started http://localhost:9000')) ================================================ FILE: examples/server-side-rendering-async-node/webpack.config.babel.js ================================================ import path from 'path' import nodeExternals from 'webpack-node-externals' import LoadablePlugin from '@loadable/webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' const DIST_PATH = path.resolve(__dirname, 'public/dist') const production = process.env.NODE_ENV === 'production' const development = !process.env.NODE_ENV || process.env.NODE_ENV === 'development' const getConfig = target => ({ name: target, mode: development ? 'development' : 'production', target, entry: `./src/client/main-${target}.js`, module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { caller: { target }, }, }, }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, 'css-loader', ], }, ], }, externals: target === 'async-node' ? ['@loadable/component', nodeExternals()] : undefined, output: { path: path.join(DIST_PATH, target), filename: production ? '[name]-bundle-[chunkhash:8].js' : '[name].js', publicPath: `/dist/${target}/`, libraryTarget: target === 'async-node' ? 'commonjs2' : undefined, }, plugins: [new LoadablePlugin(), new MiniCssExtractPlugin()], }) export default [getConfig('web'), getConfig('async-node')] ================================================ FILE: examples/suspense/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off" } } ================================================ FILE: examples/suspense/README.md ================================================ # Get the suspense example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/suspense ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run ```bash yarn dev # or yarn start ``` ================================================ FILE: examples/suspense/babel.config.js ================================================ module.exports = { presets: ['@babel/preset-react'], plugins: ['@babel/plugin-syntax-dynamic-import'], } ================================================ FILE: examples/suspense/package.json ================================================ { "private": true, "scripts": { "start": "webpack-dev-server", "dev": "webpack-dev-server" }, "devDependencies": { "@babel/core": "^7.6.4", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/preset-react": "^7.6.3", "babel-loader": "^8.0.4", "html-webpack-plugin": "^3.2.0", "webpack": "^4.29.5", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.2.0" }, "dependencies": { "@loadable/component": "^5.10.3", "moment": "^2.24.0", "react": "^16.8.3", "react-dom": "^16.8.3" } } ================================================ FILE: examples/suspense/src/Hello.js ================================================ export default () => 'Hello' ================================================ FILE: examples/suspense/src/index.js ================================================ import React, { Suspense } from 'react' import { render } from 'react-dom' import { lazy } from '@loadable/component' const Hello = lazy(() => import('./Hello')) const Moment = lazy.lib(() => import('moment')) const App = () => (
Loading...
}> {({ default: moment }) => moment().format('HH:mm')} ) const root = document.createElement('div') document.body.append(root) render(, root) ================================================ FILE: examples/suspense/webpack.config.js ================================================ const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { mode: 'development', module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: 'babel-loader', }, ], }, plugins: [new HtmlWebpackPlugin()], } ================================================ FILE: examples/typescript/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/typescript/.gitignore ================================================ public/dist ================================================ FILE: examples/typescript/README.md ================================================ # Get the SSR example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/server-side-rendering ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run locally or build and serve ```bash yarn dev # Or yarn build yarn start ``` 🍻 ================================================ FILE: examples/typescript/babel.config.js ================================================ function isWebTarget(caller) { return Boolean(caller && caller.target === 'web') } function isWebpack(caller) { return Boolean(caller && caller.name === 'babel-loader') } module.exports = api => { const web = api.caller(isWebTarget) const webpack = api.caller(isWebpack) return { presets: [ '@babel/preset-typescript', '@babel/preset-react', [ '@babel/preset-env', { useBuiltIns: web ? 'entry' : undefined, corejs: web ? 'core-js@3' : false, targets: !web ? { node: 'current' } : undefined, modules: webpack ? false : 'commonjs', }, ], ], plugins: ['@babel/plugin-syntax-dynamic-import', '@loadable/babel-plugin'], } } ================================================ FILE: examples/typescript/nodemon.json ================================================ { "ignore": ["client", "public"], "execMap": { "js": "babel-node" } } ================================================ FILE: examples/typescript/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon src/server/main.js", "build": "NODE_ENV=production yarn build:webpack && yarn build:lib", "build:dev": "NODE_ENV=development yarn build:webpack && yarn build:lib", "build:webpack": "webpack", "build:lib": "babel -d lib src", "start": "NODE_ENV=production node lib/server/main.js", "start:dev": "NODE_ENV=development node -r @babel/register lib/server/main.js" }, "devDependencies": { "@babel/cli": "^7.4.4", "@babel/core": "^7.6.2", "@babel/node": "^7.0.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.12.1", "@types/loadable__component": "^5.13.1", "@types/react": "^16.9.53", "@types/react-router-dom": "^5.1.6", "babel-loader": "^8.0.6", "css-loader": "^2.1.1", "mini-css-extract-plugin": "^0.6.0", "nodemon": "^1.19.0", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "typescript": "^4.0.3", "webpack": "^4.31.0", "webpack-cli": "^3.3.2", "webpack-dev-middleware": "^3.6.2", "webpack-node-externals": "^1.7.2" }, "dependencies": { "@babel/register": "^7.12.1", "@loadable/babel-plugin": "file:./../../packages/babel-plugin", "@loadable/component": "file:./../../packages/component", "@loadable/server": "file:./../../packages/server", "@loadable/webpack-plugin": "file:./../../packages/webpack-plugin", "core-js": "^3.0.1", "express": "^4.16.4", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/typescript/src/client/App.tsx ================================================ import * as React from 'react' import loadable from '@loadable/component' import {StaticRouter, Switch, Route} from 'react-router-dom'; const X = loadable(() => import(`./Page`)) const Y = loadable(() => import(`./PageWithParam`)) const App = () => (

Components loaded directly:


// @ts-expect-error routeProperties do not exists on X - it accepts no props at all } />
) export default App ================================================ FILE: examples/typescript/src/client/Page.tsx ================================================ import * as React from 'react'; const Page:React.FC<{}> = () => (I am lazy page); export default Page; ================================================ FILE: examples/typescript/src/client/PageWithParam.tsx ================================================ import * as React from 'react'; const PageWithParam:React.FC<{x: number}> = ({x}) => (I am lazy page2 -{x||"missed prop"}-); export default PageWithParam; ================================================ FILE: examples/typescript/src/client/main-node.js ================================================ export { default } from './App.tsx' ================================================ FILE: examples/typescript/src/client/main-web.js ================================================ import 'core-js' import React from 'react' import { hydrate } from 'react-dom' import { loadableReady } from '@loadable/component' import App from './App.tsx' console.log('waiting for application ready...') loadableReady(() => { console.log('application is ready...') const root = document.getElementById('main') hydrate(, root) }) ================================================ FILE: examples/typescript/src/server/main.js ================================================ import path from 'path' import express from 'express' import React from 'react' import { renderToString } from 'react-dom/server' import { ChunkExtractor } from '@loadable/server' const app = express() // https://github.com/gregberge/loadable-components/issues/634 // app.use('*/runtime~main.js', async (req, res, next) => { // console.log('delaying runtime chunk'); // await new Promise(resolve => setTimeout(resolve, 2000)); // next(); // }); app.use(express.static(path.join(__dirname, '../../public'))) if (process.env.NODE_ENV !== 'production') { /* eslint-disable global-require, import/no-extraneous-dependencies */ const { default: webpackConfig } = require('../../webpack.config.babel') const webpackDevMiddleware = require('webpack-dev-middleware') const webpack = require('webpack') /* eslint-enable global-require, import/no-extraneous-dependencies */ const compiler = webpack(webpackConfig) app.use( webpackDevMiddleware(compiler, { logLevel: 'silent', publicPath: '/dist/web', writeToDisk(filePath) { return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath) }, }), ) } const nodeStats = path.resolve( __dirname, '../../public/dist/node/loadable-stats.json', ) const webStats = path.resolve( __dirname, '../../public/dist/web/loadable-stats.json', ) app.get('*', (req, res) => { const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats }) const { default: App } = nodeExtractor.requireEntrypoint() const webExtractor = new ChunkExtractor({ statsFile: webStats }) const jsx = webExtractor.collectChunks() const html = renderToString(jsx) res.set('content-type', 'text/html') res.send(` ${webExtractor.getLinkTags()} ${webExtractor.getStyleTags()}
${html}
${webExtractor.getScriptTags()} `) }) // eslint-disable-next-line no-console app.listen(9000, () => console.log('Server started http://localhost:9000')) ================================================ FILE: examples/typescript/tsconfig.json ================================================ { "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ // "outDir": "./", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "skipLibCheck": true /* Skip type checking of declaration files. */, "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ "jsx": "react" } } ================================================ FILE: examples/typescript/webpack.config.babel.js ================================================ import path from 'path' import nodeExternals from 'webpack-node-externals' import LoadablePlugin from '@loadable/webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' const DIST_PATH = path.resolve(__dirname, 'public/dist') const production = process.env.NODE_ENV === 'production' const development = !production const getConfig = target => ({ name: target, mode: development ? 'development' : 'production', target, entry: `./src/client/main-${target}.js`, module: { rules: [ { test: /\.([jt])sx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { caller: { target }, }, }, }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, 'css-loader', ], }, ], }, externals: target === 'node' ? ['@loadable/component', nodeExternals()] : undefined, optimization: { runtimeChunk: target !== 'node', }, resolve: { extensions: ['.tsx', '.ts', '.js', '.css'], }, output: { path: path.join(DIST_PATH, target), filename: production ? '[name]-bundle-[chunkhash:8].js' : '[name].js', publicPath: `/dist/${target}/`, libraryTarget: target === 'node' ? 'commonjs2' : undefined, }, plugins: [new LoadablePlugin(), new MiniCssExtractPlugin()], }) export default [getConfig('web'), getConfig('node')] ================================================ FILE: examples/webpack/README.md ================================================ these examples are also **tests** ================================================ FILE: examples/webpack/webpack4/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/webpack/webpack4/.gitignore ================================================ public/dist ================================================ FILE: examples/webpack/webpack4/README.md ================================================ # Get the SSR example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/server-side-rendering ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run locally or build and serve ```bash yarn dev # Or yarn build yarn start ``` 🍻 ================================================ FILE: examples/webpack/webpack4/babel.config.js ================================================ function isWebTarget(caller) { return Boolean(caller && caller.target === 'web') } function isWebpack(caller) { return Boolean(caller && caller.name === 'babel-loader') } module.exports = api => { const web = api.caller(isWebTarget) const webpack = api.caller(isWebpack) return { presets: [ '@babel/preset-react', [ '@babel/preset-env', { useBuiltIns: web ? 'entry' : undefined, corejs: web ? 'core-js@3' : false, targets: !web ? { node: 'current' } : undefined, modules: webpack ? false : 'commonjs', }, ], ], plugins: ['@babel/plugin-syntax-dynamic-import', '@loadable/babel-plugin'], } } ================================================ FILE: examples/webpack/webpack4/nodemon.json ================================================ { "ignore": ["client", "public"], "execMap": { "js": "babel-node" } } ================================================ FILE: examples/webpack/webpack4/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon src/server/main.js", "build": "NODE_ENV=production yarn build:webpack && yarn build:lib", "build:dev": "NODE_ENV=development yarn build:webpack && yarn build:lib", "build:webpack": "webpack", "build:lib": "babel -d lib src", "start": "NODE_ENV=production node lib/server/main.js", "start:dev": "NODE_ENV=development node -r @babel/register lib/server/main.js", "update": "rm ./node_modules/.yarn-integrity && yarn" }, "devDependencies": { "@babel/cli": "^7.4.4", "@babel/core": "^7.6.2", "@babel/node": "^7.0.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "babel-loader": "^8.0.6", "css-loader": "^2.1.1", "mini-css-extract-plugin": "^0.6.0", "nodemon": "^1.19.0", "webpack": "^4.31.0", "webpack-cli": "^3.3.2", "webpack-dev-middleware": "^3.6.2", "webpack-node-externals": "^1.7.2" }, "dependencies": { "@babel/register": "^7.12.1", "@loadable/babel-plugin": "file:./../../../packages/babel-plugin", "@loadable/component": "file:./../../../packages/component", "@loadable/server": "file:./../../../packages/server", "@loadable/webpack-plugin": "file:./../../../packages/webpack-plugin", "core-js": "^3.0.1", "express": "^4.16.4", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/webpack/webpack4/src/client/App.js ================================================ import React from 'react' import loadable from '@loadable/component' const X = loadable(props => import(`./letters/${props.letter}`)) const ClientSideOnly = loadable(props => import(`./letters/${props.letter}`), { ssr: false, }) const Moment = loadable.lib(() => import('moment'), { resolveComponent: moment => moment.default || moment, }) const App = () => (

Lazy load letter A:

Lazy load letter B:

Lazy load letter only on Client C and D: +

lazy load momentjs and format date: {moment => `now is : ${moment().format('HH:mm')}`}

) export default App ================================================ FILE: examples/webpack/webpack4/src/client/letters/A.css ================================================ /* A CSS */ ================================================ FILE: examples/webpack/webpack4/src/client/letters/A.js ================================================ import './A.css' const A = () => 'Lazy-Letter-A' export default A ================================================ FILE: examples/webpack/webpack4/src/client/letters/B.js ================================================ const B = () => 'Lazy-Letter-B' export default B ================================================ FILE: examples/webpack/webpack4/src/client/letters/C.js ================================================ const C = () => 'Lazy-Letter-C' export default C ================================================ FILE: examples/webpack/webpack4/src/client/letters/D.js ================================================ // named as C const C = () => 'and-D' export default C ================================================ FILE: examples/webpack/webpack4/src/client/main-node.js ================================================ export { default } from './App' ================================================ FILE: examples/webpack/webpack4/src/client/main-web.js ================================================ import 'core-js' import React from 'react' import { hydrate } from 'react-dom' import { loadableReady } from '@loadable/component' import App from './App' console.log('waiting for application ready...') loadableReady(() => { console.log('application is ready...') const root = document.getElementById('main') hydrate(, root) }) ================================================ FILE: examples/webpack/webpack4/src/server/main.js ================================================ import path from 'path' import express from 'express' import React from 'react' import { renderToString } from 'react-dom/server' import { ChunkExtractor } from '@loadable/server' const app = express() // https://github.com/gregberge/loadable-components/issues/634 app.use('*/runtime~main*.js', async (req, res, next) => { console.log('delaying runtime chunk') await new Promise(resolve => setTimeout(resolve, 2000)) next() }) app.use('*/letters*.js', async (req, res, next) => { console.log('delaying letters chunk') await new Promise(resolve => setTimeout(resolve, 1000)) next() }) app.use(express.static(path.join(__dirname, '../../public'))) if (process.env.NODE_ENV !== 'production') { /* eslint-disable global-require, import/no-extraneous-dependencies */ const { default: webpackConfig } = require('../../webpack.config.babel') const webpackDevMiddleware = require('webpack-dev-middleware') const webpack = require('webpack') /* eslint-enable global-require, import/no-extraneous-dependencies */ const compiler = webpack(webpackConfig) app.use( webpackDevMiddleware(compiler, { logLevel: 'silent', publicPath: '/dist/web', writeToDisk(filePath) { return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath) }, }), ) } const nodeStats = path.resolve( __dirname, '../../public/dist/node/loadable-stats.json', ) const webStats = path.resolve( __dirname, '../../public/dist/web/loadable-stats.json', ) app.get('*', (req, res) => { const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats }) const { default: App } = nodeExtractor.requireEntrypoint() const webExtractor = new ChunkExtractor({ statsFile: webStats }) const jsx = webExtractor.collectChunks() const html = renderToString(jsx) res.set('content-type', 'text/html') res.send(` ${webExtractor.getLinkTags()} ${webExtractor.getStyleTags()}
${html}
${webExtractor.getScriptTags()} `) }) // eslint-disable-next-line no-console app.listen(9000, () => console.log('Server started http://localhost:9000')) ================================================ FILE: examples/webpack/webpack4/webpack.config.babel.js ================================================ import path from 'path' import nodeExternals from 'webpack-node-externals' import LoadablePlugin from '@loadable/webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' const DIST_PATH = path.resolve(__dirname, 'public/dist') const production = process.env.NODE_ENV === 'production' const development = !production const getConfig = target => ({ name: target, mode: development ? 'development' : 'production', target, entry: `./src/client/main-${target}.js`, module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { caller: { target }, }, }, }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, 'css-loader', ], }, ], }, externals: target === 'node' ? ['@loadable/component', nodeExternals()] : undefined, optimization: { runtimeChunk: target !== 'node', }, output: { path: path.join(DIST_PATH, target), filename: production ? '[name]-bundle-[chunkhash:8].js' : '[name].js', publicPath: `/dist/${target}/`, libraryTarget: target === 'node' ? 'commonjs2' : undefined, }, plugins: [new LoadablePlugin(), new MiniCssExtractPlugin()], }) export default [getConfig('web'), getConfig('node')] ================================================ FILE: examples/webpack/webpack5/.eslintrc.json ================================================ { "env": { "browser": true }, "rules": { "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off" } } ================================================ FILE: examples/webpack/webpack5/.gitignore ================================================ public/dist ================================================ FILE: examples/webpack/webpack5/README.md ================================================ # Get the SSR example running Steps: 1. Download repository ```bash git clone https://github.com/gregberge/loadable-components.git ``` 2. move into example directory ```bash cd ./loadable-components/examples/server-side-rendering ``` 3. install [https://yarnpkg.com/lang/en/docs/install](yarn) if haven't already 4. install project dependencies ```bash yarn ``` 5. run locally or build and serve ```bash yarn dev # Or yarn build yarn start ``` 🍻 ================================================ FILE: examples/webpack/webpack5/babel.config.js ================================================ function isWebTarget(caller) { return Boolean(caller && caller.target === 'web') } function isWebpack(caller) { return Boolean(caller && caller.name === 'babel-loader') } module.exports = api => { const web = api.caller(isWebTarget) const webpack = api.caller(isWebpack) return { presets: [ '@babel/preset-react', [ '@babel/preset-env', { useBuiltIns: web ? 'entry' : undefined, corejs: web ? 'core-js@3' : false, targets: !web ? { node: 'current' } : undefined, modules: webpack ? false : 'commonjs', }, ], ], plugins: ['@babel/plugin-syntax-dynamic-import', '@loadable/babel-plugin'], } } ================================================ FILE: examples/webpack/webpack5/nodemon.json ================================================ { "ignore": ["client", "public"], "execMap": { "js": "babel-node" } } ================================================ FILE: examples/webpack/webpack5/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon src/server/main.js", "build": "NODE_ENV=production yarn build:webpack && yarn build:lib", "build:dev": "NODE_ENV=development yarn build:webpack && yarn build:lib", "build:webpack": "webpack", "build:lib": "babel -d lib src", "start": "NODE_ENV=production node lib/server/main.js", "start:dev": "NODE_ENV=development node -r @babel/register lib/server/main.js", "update": "rm ./node_modules/.yarn-integrity && yarn" }, "devDependencies": { "@babel/cli": "^7.4.4", "@babel/core": "^7.6.2", "@babel/node": "^7.0.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "babel-loader": "^8.1.0", "css-loader": "^5.0.0", "mini-css-extract-plugin": "^1.1.0", "nodemon": "^1.19.0", "webpack": "^5.17.0", "webpack-cli": "^4.1.0", "webpack-dev-middleware": "^3.7.2", "webpack-node-externals": "^2.5.2" }, "dependencies": { "@babel/register": "^7.12.1", "@loadable/babel-plugin": "file:./../../../packages/babel-plugin", "@loadable/component": "file:./../../../packages/component", "@loadable/server": "file:./../../../packages/server", "@loadable/webpack-plugin": "file:./../../../packages/webpack-plugin", "core-js": "^3.0.1", "express": "^4.16.4", "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6" } } ================================================ FILE: examples/webpack/webpack5/src/client/App.js ================================================ import React from 'react' import loadable from '@loadable/component' const X = loadable(props => import(`./letters/${props.letter}`)) const ClientSideOnly = loadable(props => import(`./letters/${props.letter}`), { ssr: false, }) const Moment = loadable.lib(() => import('moment'), { resolveComponent: moment => moment.default || moment, }) const App = () => (

Lazy load letter A:

Lazy load letter B:

Lazy load letter only on Client C and D: +

lazy load momentjs and format date: {moment => `now is : ${moment().format('HH:mm')}`}

) export default App ================================================ FILE: examples/webpack/webpack5/src/client/letters/A.css ================================================ /* A CSS */ ================================================ FILE: examples/webpack/webpack5/src/client/letters/A.js ================================================ import './A.css' const A = () => 'Lazy-Letter-A' export default A ================================================ FILE: examples/webpack/webpack5/src/client/letters/B.js ================================================ const B = () => 'Lazy-Letter-B' export default B ================================================ FILE: examples/webpack/webpack5/src/client/letters/C.js ================================================ const C = () => 'Lazy-Letter-C' export default C ================================================ FILE: examples/webpack/webpack5/src/client/letters/D.js ================================================ // named as C const C = () => 'and-D' export default C ================================================ FILE: examples/webpack/webpack5/src/client/main-node.js ================================================ export { default } from './App' ================================================ FILE: examples/webpack/webpack5/src/client/main-web.js ================================================ import 'core-js' import React from 'react' import { hydrate } from 'react-dom' import { loadableReady } from '@loadable/component' import App from './App' console.log('waiting for application ready...') loadableReady(() => { console.log('application is ready...') const root = document.getElementById('main') hydrate(, root) }) ================================================ FILE: examples/webpack/webpack5/src/server/main.js ================================================ import path from 'path' import express from 'express' import React from 'react' import { renderToString } from 'react-dom/server' import { ChunkExtractor } from '@loadable/server' const app = express() // https://github.com/gregberge/loadable-components/issues/634 // app.use('*/runtime~main.js', async (req, res, next) => { // console.log('delaying runtime chunk'); // await new Promise(resolve => setTimeout(resolve, 2000)); // next(); // }); app.use(express.static(path.join(__dirname, '../../public'))) if (process.env.NODE_ENV !== 'production') { /* eslint-disable global-require, import/no-extraneous-dependencies */ const { default: webpackConfig } = require('../../webpack.config.babel') const webpackDevMiddleware = require('webpack-dev-middleware') const webpack = require('webpack') /* eslint-enable global-require, import/no-extraneous-dependencies */ const compiler = webpack(webpackConfig) app.use( webpackDevMiddleware(compiler, { logLevel: 'silent', publicPath: '/dist/web', writeToDisk(filePath) { return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath) }, }), ) } const nodeStats = path.resolve( __dirname, '../../public/dist/node/loadable-stats.json', ) const webStats = path.resolve( __dirname, '../../public/dist/web/loadable-stats.json', ) app.get('*', (req, res) => { const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats }) const { default: App } = nodeExtractor.requireEntrypoint() const webExtractor = new ChunkExtractor({ statsFile: webStats }) const jsx = webExtractor.collectChunks() const html = renderToString(jsx) res.set('content-type', 'text/html') res.send(` ${webExtractor.getLinkTags()} ${webExtractor.getStyleTags()}
${html}
${webExtractor.getScriptTags()} `) }) // eslint-disable-next-line no-console app.listen(9000, () => console.log('Server started http://localhost:9000')) ================================================ FILE: examples/webpack/webpack5/webpack.config.babel.js ================================================ import path from 'path' import nodeExternals from 'webpack-node-externals' import LoadablePlugin from '@loadable/webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' const DIST_PATH = path.resolve(__dirname, 'public/dist') const production = process.env.NODE_ENV === 'production' const development = !production const getConfig = target => ({ name: target, mode: development ? 'development' : 'production', target, entry: `./src/client/main-${target}.js`, module: { rules: [ { test: /\.js?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { caller: { target }, }, }, }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, 'css-loader', ], }, ], }, externals: target === 'node' ? ['@loadable/component', nodeExternals()] : undefined, optimization: { // this will lead to runtime error runtimeChunk: target !== 'node', }, output: { path: path.join(DIST_PATH, target), filename: production ? '[name]-bundle-[chunkhash:8].js' : '[name].js', publicPath: `/dist/${target}/`, libraryTarget: target === 'node' ? 'commonjs2' : undefined, }, plugins: [new LoadablePlugin(), new MiniCssExtractPlugin()], }) export default [getConfig('web'), getConfig('node')] ================================================ FILE: lerna.json ================================================ { "lerna": "2.9.0", "packages": [ "packages/*" ], "version": "5.16.7", "npmClient": "yarn", "useWorkspaces": true } ================================================ FILE: netlify.toml ================================================ [build] base = "website" command = "yarn build" publish = "website/public" ================================================ FILE: package.json ================================================ { "name": "loadable-components", "private": true, "workspaces": [ "packages/*" ], "bundlesize": [ { "path": "./packages/component/dist/loadable.min.js", "maxSize": "3.5 kB" }, { "path": "./packages/component/dist/loadable.esm.js", "maxSize": "4.5 kB" } ], "scripts": { "build": "lerna run build", "ci": "yarn build && yarn lint && yarn test:prepare && yarn test --ci", "dev": "WATCH_MODE=true lerna run build --parallel -- --watch", "format": "prettier --write \"**/*.{js,json,md}\"", "lint": "eslint .", "release": "lerna publish --conventional-commits && conventional-github-releaser --preset angular", "release-to-git": "./scripts/git-release.sh", "test:prepare": "./scripts/prepare.sh", "test": "jest" }, "devDependencies": { "@babel/cli": "^7.7.7", "@babel/core": "^7.7.7", "@babel/node": "^7.7.7", "@babel/plugin-proposal-class-properties": "^7.7.4", "@babel/plugin-transform-runtime": "^7.7.6", "@babel/preset-env": "^7.7.7", "@babel/preset-react": "^7.7.4", "@hedgepigdaniel/npm-publish-git": "^0.1.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.4.0", "babel-core": "^7.0.0-bridge.0", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "babel-plugin-annotate-pure-calls": "^0.4.0", "conventional-github-releaser": "^3.1.2", "cross-env": "^6.0.3", "eslint": "^6.8.0", "eslint-config-airbnb": "^18.0.1", "eslint-config-prettier": "^6.9.0", "eslint-plugin-import": "^2.19.1", "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-react": "^7.17.0", "jest": "^24.9.0", "lerna": "^3.20.2", "prettier": "^1.19.1", "react": "^16.12.0", "react-dom": "^16.12.0", "regenerator-runtime": "^0.13.3", "rollup": "^1.29.0", "rollup-plugin-babel": "^4.3.2", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.0.1", "rollup-plugin-replace": "^2.2.0", "rollup-plugin-terser": "^5.1.3", "shx": "^0.3.2" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } ================================================ FILE: packages/babel-plugin/CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [5.16.1](https://github.com/gregberge/loadable-components/compare/v5.16.0...v5.16.1) (2023-07-20) ### Bug Fixes * correct babel plugin default signature to allow any source of 'loadable' ([#972](https://github.com/gregberge/loadable-components/issues/972)) ([19849b6](https://github.com/gregberge/loadable-components/commit/19849b6ba738fe19c18e61ed3402ee82ba934760)), closes [#971](https://github.com/gregberge/loadable-components/issues/971) # [5.16.0](https://github.com/gregberge/loadable-components/compare/v5.15.3...v5.16.0) (2023-07-09) ### Features * Allow additional identifiers to be passed in to the babel plugin ([#966](https://github.com/gregberge/loadable-components/issues/966)) ([e18e37a](https://github.com/gregberge/loadable-components/commit/e18e37afd8b30455d3a786b9b0dae5f3bd0d442b)) ## [5.15.3](https://github.com/gregberge/loadable-components/compare/v5.15.2...v5.15.3) (2023-01-28) **Note:** Version bump only for package @loadable/babel-plugin ## [5.13.2](https://github.com/gregberge/loadable-components/compare/v5.13.1...v5.13.2) (2020-09-14) **Note:** Version bump only for package @loadable/babel-plugin # [5.13.0](https://github.com/gregberge/loadable-components/compare/v5.12.0...v5.13.0) (2020-06-29) ### Bug Fixes * allow webpack cache is ready only for initial chunks, fixes [#558](https://github.com/gregberge/loadable-components/issues/558) ([61f8b75](https://github.com/gregberge/loadable-components/commit/61f8b75b54612368c88807d73abb7dc7add720ad)) * **babel-plugin:** add missing peer dependency ([#524](https://github.com/gregberge/loadable-components/issues/524)) ([03a79b6](https://github.com/gregberge/loadable-components/commit/03a79b66defc78f150436acd6a9d3e029bb1d470)) # [5.12.0](https://github.com/gregberge/loadable-components/compare/v5.11.0...v5.12.0) (2020-01-09) ### Bug Fixes * apply loadable transformations before any other, fixes [#466](https://github.com/gregberge/loadable-components/issues/466) ([ac5ba45](https://github.com/gregberge/loadable-components/commit/ac5ba45862bad68b971a969e6e8713874add51a6)) # [5.11.0](https://github.com/smooth-code/loadable-components/compare/v5.10.3...v5.11.0) (2019-12-02) ### Bug Fixes * fix isReady problem ([#445](https://github.com/smooth-code/loadable-components/issues/445)) ([3024348](https://github.com/smooth-code/loadable-components/commit/30243482be917e89515d057e2368e7278e34696c)), closes [#400](https://github.com/smooth-code/loadable-components/issues/400) ## [5.10.3](https://github.com/smooth-code/loadable-components/compare/v5.10.2...v5.10.3) (2019-09-24) ### Bug Fixes * **babel-plugin:** fix bug when using + concatenation instead of a template literal ([#425](https://github.com/smooth-code/loadable-components/issues/425)) ([d98dd27](https://github.com/smooth-code/loadable-components/commit/d98dd27)) # [5.10.0](https://github.com/smooth-code/loadable-components/compare/v5.9.0...v5.10.0) (2019-05-13) ### Bug Fixes * fix chunkname mismatch ([#332](https://github.com/smooth-code/loadable-components/issues/332)) ([7ffaa4c](https://github.com/smooth-code/loadable-components/commit/7ffaa4c)), closes [#331](https://github.com/smooth-code/loadable-components/issues/331) # [5.8.0](https://github.com/smooth-code/loadable-components/compare/v5.7.2...v5.8.0) (2019-04-10) ### Bug Fixes * **babel-plugin:** Use require.resolve instead of relative path resolution ([#303](https://github.com/smooth-code/loadable-components/issues/303)) ([bad7f1f](https://github.com/smooth-code/loadable-components/commit/bad7f1f)) ## [5.7.2](https://github.com/smooth-code/loadable-components/compare/v5.7.1...v5.7.2) (2019-03-20) ### Bug Fixes * **babel-plugin:** handle "-" at the end of request ([c0f325b](https://github.com/smooth-code/loadable-components/commit/c0f325b)) ## [5.7.1](https://github.com/smooth-code/loadable-components/compare/v5.7.0...v5.7.1) (2019-03-19) ### Bug Fixes * **babel-plugin:** handle special chars in file names ([#279](https://github.com/smooth-code/loadable-components/issues/279)) ([4da39ff](https://github.com/smooth-code/loadable-components/commit/4da39ff)) # [5.7.0](https://github.com/smooth-code/loadable-components/compare/v5.6.1...v5.7.0) (2019-03-14) ### Performance Improvements * **build:** add build target for Node ([#267](https://github.com/smooth-code/loadable-components/issues/267)) ([97ff6ac](https://github.com/smooth-code/loadable-components/commit/97ff6ac)) # [5.6.0](https://github.com/smooth-code/loadable-components/compare/v5.5.0...v5.6.0) (2019-02-05) ### Bug Fixes * **server:** fix chunkName resolving ([#219](https://github.com/smooth-code/loadable-components/issues/219)) ([ef11e11](https://github.com/smooth-code/loadable-components/commit/ef11e11)) ### Features * **babel-plugin:** transform code annotated with magic comment ([4f832dc](https://github.com/smooth-code/loadable-components/commit/4f832dc)), closes [#192](https://github.com/smooth-code/loadable-components/issues/192) # [5.5.0](https://github.com/smooth-code/loadable-components/compare/v5.4.0...v5.5.0) (2019-01-22) **Note:** Version bump only for package @loadable/babel-plugin ## [5.2.2](https://github.com/smooth-code/loadable-components/compare/v5.2.1...v5.2.2) (2018-12-12) ### Bug Fixes * **babel-plugin:** fix chunkName with aggressive code splitting ([e974933](https://github.com/smooth-code/loadable-components/commit/e974933)), closes [#182](https://github.com/smooth-code/loadable-components/issues/182) # [5.0.0](https://github.com/smooth-code/loadable-components/compare/v4.0.5...v5.0.0) (2018-11-10) ### Features * improve SSR support ([eb1cfe8](https://github.com/smooth-code/loadable-components/commit/eb1cfe8)) ### BREAKING CHANGES * - SSR has been rewritten from scratch, if you use it, please follow the new guide. - Prefetch component and prefetch functions have been removed, please use `webpackPrefetch` instead. ## [4.0.5](https://github.com/smooth-code/loadable-components/compare/v4.0.4...v4.0.5) (2018-11-01) **Note:** Version bump only for package @loadable/babel-plugin ## [4.0.3](https://github.com/smooth-code/loadable-components/compare/v4.0.2...v4.0.3) (2018-10-31) ### Bug Fixes * **server:** disable common chunks optim ([78e7b28](https://github.com/smooth-code/loadable-components/commit/78e7b28)) ## [4.0.2](https://github.com/smooth-code/loadable-components/compare/v4.0.1...v4.0.2) (2018-10-31) ### Bug Fixes * **babel-plugin:** transform into friendly chunk name ([54422cb](https://github.com/smooth-code/loadable-components/commit/54422cb)) # [4.0.0](https://github.com/smooth-code/loadable-components/compare/v3.0.2...v4.0.0) (2018-10-30) ### Features * add new loadable.lib, change API ([94b2e87](https://github.com/smooth-code/loadable-components/commit/94b2e87)) ### BREAKING CHANGES * - `ErrorComponent` is ignored, please use Error Boundaries to handle errors. - `lazy` is no longer exported - `LoadingComponent` is replaced by `fallback` option - `ref` are now forwarded # [3.0.0](https://github.com/smooth-code/loadable-components/compare/v2.2.3...v3.0.0) (2018-10-29) ### Features * welcome loadable ([4dffad7](https://github.com/smooth-code/loadable-components/commit/4dffad7)) ### BREAKING CHANGES * API has completely changed, see documentation. ================================================ FILE: packages/babel-plugin/README.md ================================================ # @loadable/babel-plugin This plugin is required only if you use Server Side Rendering in your application. [See `@loadable/server` for more information](https://loadable-components.com/docs/api-loadable-server/). ## Install ``` npm install --save-dev @loadable/babel-plugin ``` ## Documentation 👉 [See full documentation](https://loadable-components.com/) ## License MIT ================================================ FILE: packages/babel-plugin/package.json ================================================ { "name": "@loadable/babel-plugin", "description": "Babel plugin for loadable (required for SSR).", "version": "5.16.1", "main": "lib/index.js", "repository": "git@github.com:gregberge/loadable-components.git", "author": "Greg Bergé ", "publishConfig": { "access": "public" }, "keywords": [ "loadable" ], "engines": { "node": ">=8" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" }, "license": "MIT", "scripts": { "prebuild": "shx rm -rf lib", "build": "BUILD_TARGET=node babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src", "prepublishOnly": "yarn run build" }, "dependencies": { "@babel/plugin-syntax-dynamic-import": "^7.7.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } } ================================================ FILE: packages/babel-plugin/src/__snapshots__/index.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`plugin Magic comment should remove only needed comments 1`] = ` "const load = /* IMPORTANT! */ { resolved: {}, chunkName() { return \\"moment\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"moment\\" */ 'moment'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"moment\\"); } return eval('require.resolve')(\\"moment\\"); } };" `; exports[`plugin Magic comment should transpile arrow functions 1`] = ` "const load = { resolved: {}, chunkName() { return \\"moment\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"moment\\" */ 'moment'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"moment\\"); } return eval('require.resolve')(\\"moment\\"); } };" `; exports[`plugin Magic comment should transpile function expression 1`] = ` "const load = { resolved: {}, chunkName() { return \\"moment\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: function () { return import( /* webpackChunkName: \\"moment\\" */ 'moment'); }, requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"moment\\"); } return eval('require.resolve')(\\"moment\\"); } };" `; exports[`plugin Magic comment should transpile shortand properties 1`] = ` "const obj = { load: { resolved: {}, chunkName() { return \\"moment\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => { return import( /* webpackChunkName: \\"moment\\" */ 'moment'); }, requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"moment\\"); } return eval('require.resolve')(\\"moment\\"); } } };" `; exports[`plugin aggressive import should work with destructuration 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName({ foo }) { return \`\${foo}\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: ({ foo }) => import( /* webpackChunkName: \\"[request]\\" */ \`./\${foo}\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve({ foo }) { if (require.resolveWeak) { return require.resolveWeak(\`./\${foo}\`); } return eval('require.resolve')(\`./\${foo}\`); } });" `; exports[`plugin aggressive import with "webpackChunkName" should keep it 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName(props) { return \\"pages/\\" + props.path.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: props => import( /* webpackChunkName: \\"pages/[request]\\" */ \`./pages/\${props.path}\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve(props) { if (require.resolveWeak) { return require.resolveWeak(\`./pages/\${props.path}\`); } return eval('require.resolve')(\`./pages/\${props.path}\`); } });" `; exports[`plugin aggressive import with "webpackChunkName" should replace it 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName(props) { return \`\${props.foo}\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: props => import( /* webpackChunkName: \\"[request]\\" */ \`./\${props.foo}\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve(props) { if (require.resolveWeak) { return require.resolveWeak(\`./\${props.foo}\`); } return eval('require.resolve')(\`./\${props.foo}\`); } });" `; exports[`plugin aggressive import without "webpackChunkName" should support complex request 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName(props) { return \`dir-\${props.foo}-test\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: props => import( /* webpackChunkName: \\"dir-[request]\\" */ \`./dir/\${props.foo}/test\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve(props) { if (require.resolveWeak) { return require.resolveWeak(\`./dir/\${props.foo}/test\`); } return eval('require.resolve')(\`./dir/\${props.foo}/test\`); } });" `; exports[`plugin aggressive import without "webpackChunkName" should support destructuring 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName({ foo }) { return \`dir-\${foo}-test\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: ({ foo }) => import( /* webpackChunkName: \\"dir-[request]\\" */ \`./dir/\${foo}/test\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve({ foo }) { if (require.resolveWeak) { return require.resolveWeak(\`./dir/\${foo}/test\`); } return eval('require.resolve')(\`./dir/\${foo}/test\`); } });" `; exports[`plugin aggressive import without "webpackChunkName" should support simple request 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName(props) { return \`\${props.foo}\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: props => import( /* webpackChunkName: \\"[request]\\" */ \`./\${props.foo}\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve(props) { if (require.resolveWeak) { return require.resolveWeak(\`./\${props.foo}\`); } return eval('require.resolve')(\`./\${props.foo}\`); } });" `; exports[`plugin custom signatures (default) should support old named import 1`] = ` "import loadable from './loadable-utils'; loadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin custom signatures named signature should not match default import 1`] = ` "import myLoadable from 'myLoadablePackage'; myLoadable(() => import(\`./ModA\`));" `; exports[`plugin custom signatures should match custom default signature 1`] = ` "import myLoadable from 'myLoadablePackage'; myLoadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin custom signatures should match custom named signature 1`] = ` "import { myLoadable } from 'myLoadablePackage'; myLoadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin custom signatures should match renamed default import 1`] = ` "import renamedLoadable from '@loadable/component'; renamedLoadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin custom signatures should match simple default import 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin custom signatures should not match on undeclared specifiers 1`] = ` "import myLoadable from 'myLoadablePackage'; myLoadable(() => import(\`./ModA\`));" `; exports[`plugin loadable.lib should be transpiled too 1`] = ` "import loadable from '@loadable/component'; loadable.lib({ resolved: {}, chunkName() { return \\"moment\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"moment\\" */ 'moment'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"moment\\"); } return eval('require.resolve')(\\"moment\\"); } });" `; exports[`plugin simple import in a complex promise should work 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"ModA\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => timeout(import( /* webpackChunkName: \\"ModA\\" */ './ModA'), 2000), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"./ModA\\"); } return eval('require.resolve')(\\"./ModA\\"); } });" `; exports[`plugin simple import should transform path into "chunk-friendly" name 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"foo-bar\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"foo-bar\\" */ '../foo/bar'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"../foo/bar\\"); } return eval('require.resolve')(\\"../foo/bar\\"); } });" `; exports[`plugin simple import should work with * in name 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \`foo\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"foo\\" */ \`./foo*\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./foo*\`); } return eval('require.resolve')(\`./foo*\`); } });" `; exports[`plugin simple import should work with + concatenation 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"\\" */ './Mod' + 'A'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak('./Mod' + 'A'); } return eval('require.resolve')('./Mod' + 'A'); } });" `; exports[`plugin simple import should work with lazy if imported 1`] = ` "import { lazy } from '@loadable/component'; lazy({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin simple import should work with renamed lazy specifier 1`] = ` "import { lazy as renamedLazy } from '@loadable/component'; renamedLazy({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin simple import should work with renamed specifier by default 1`] = ` "import renamedLoadable from '@loadable/component'; renamedLoadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin simple import should work with template literal 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \`ModA\`.replace(/[^a-zA-Z0-9_!§$()=\\\\-^°]+/g, \\"-\\"); }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ \`./ModA\`), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\`./ModA\`); } return eval('require.resolve')(\`./ModA\`); } });" `; exports[`plugin simple import with "webpackChunkName" comment should use it 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"ChunkA\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ChunkA\\" */ './ModA'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"./ModA\\"); } return eval('require.resolve')(\\"./ModA\\"); } });" `; exports[`plugin simple import with "webpackChunkName" comment should use it even if comment is separated by "," 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"ChunkA\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackPrefetch: true, webpackChunkName: \\"ChunkA\\" */ './ModA'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"./ModA\\"); } return eval('require.resolve')(\\"./ModA\\"); } });" `; exports[`plugin simple import without "webpackChunkName" comment should add it 1`] = ` "import loadable from '@loadable/component'; loadable({ resolved: {}, chunkName() { return \\"ModA\\"; }, isReady(props) { const key = this.resolve(props); if (this.resolved[key] !== true) { return false; } if (typeof __webpack_modules__ !== 'undefined') { return !!__webpack_modules__[key]; } return false; }, importAsync: () => import( /* webpackChunkName: \\"ModA\\" */ './ModA'), requireAsync(props) { const key = this.resolve(props); this.resolved[key] = false; return this.importAsync(props).then(resolved => { this.resolved[key] = true; return resolved; }); }, requireSync(props) { const id = this.resolve(props); if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id); } return eval('module.require')(id); }, resolve() { if (require.resolveWeak) { return require.resolveWeak(\\"./ModA\\"); } return eval('require.resolve')(\\"./ModA\\"); } });" `; ================================================ FILE: packages/babel-plugin/src/index.js ================================================ import { declare } from "@babel/helper-plugin-utils"; import syntaxDynamicImport from '@babel/plugin-syntax-dynamic-import' import chunkNameProperty from './properties/chunkName' import isReadyProperty from './properties/isReady' import importAsyncProperty from './properties/importAsync' import requireAsyncProperty from './properties/requireAsync' import requireSyncProperty from './properties/requireSync' import resolveProperty from './properties/resolve' import stateProperty from './properties/state' const properties = [ stateProperty, chunkNameProperty, isReadyProperty, importAsyncProperty, requireAsyncProperty, requireSyncProperty, resolveProperty, ] const LOADABLE_COMMENT = '#__LOADABLE__' const DEFAULT_SIGNATURE = [{name: 'default', from: '@loadable/component'}]; const loadablePlugin = declare((api, { signatures = DEFAULT_SIGNATURE }) => { const { types: t } = api function collectImportCallPaths(startPath) { const imports = [] startPath.traverse({ Import(importPath) { imports.push(importPath.parentPath) }, }) return imports } const propertyFactories = properties.map(init => init(api)) function isValidIdentifier(path, loadableImportSpecifiers, lazyImportSpecifier) { // loadable signatures if (loadableImportSpecifiers.find(specifier => path.get('callee').isIdentifier({ name: specifier }))) { return true } // `lazy()` if (lazyImportSpecifier && path.get('callee').isIdentifier({ name: lazyImportSpecifier })) { return true } // `loadable.lib()` return ( path.get('callee').isMemberExpression() && loadableImportSpecifiers.find(specifier => path.get('callee.object').isIdentifier({ name: specifier })) && path.get('callee.property').isIdentifier({ name: 'lib' }) ) } function hasLoadableComment(path) { const comments = path.get('leadingComments') const comment = comments.find( ({ node }) => node && node.value && String(node.value).includes(LOADABLE_COMMENT), ) if (!comment) return false comment.remove() return true } function getFuncPath(path) { const funcPath = path.isCallExpression() ? path.get('arguments.0') : path if ( !funcPath.isFunctionExpression() && !funcPath.isArrowFunctionExpression() && !funcPath.isObjectMethod() ) { return null } return funcPath } function transformImport(path) { const callPaths = collectImportCallPaths(path) // Ignore loadable function that does not have any "import" call if (callPaths.length === 0) return // Multiple imports call is not supported if (callPaths.length > 1) { throw new Error( 'loadable: multiple import calls inside `loadable()` function are not supported.', ) } const [callPath] = callPaths const funcPath = getFuncPath(path) if (!funcPath) return funcPath.node.params = funcPath.node.params || [] const object = t.objectExpression( propertyFactories.map(getProperty => getProperty({ path, callPath, funcPath }), ), ) if (funcPath.isObjectMethod()) { funcPath.replaceWith( t.objectProperty(funcPath.node.key, object, funcPath.node.computed), ) } else { funcPath.replaceWith(object) } } return { inherits: syntaxDynamicImport, visitor: { Program: { enter(programPath) { let lazyImportSpecifier = false // default to "loadable" detection. Remove defaults if signatures are configured const loadableSpecifiers = signatures === DEFAULT_SIGNATURE ? ['loadable']: []; programPath.traverse({ ImportDefaultSpecifier(path) { const { parent } = path const { local } = path.node if (local && signatures.find(signature => signature.name === 'default' && parent.source.value === signature.from)) { loadableSpecifiers.push(local.name) } }, ImportSpecifier(path) { const { parent } = path const { imported, local } = path.node if (!lazyImportSpecifier) { lazyImportSpecifier = parent.source.value == '@loadable/component' && imported && imported.name == 'lazy' && local && local.name } if (local && imported && signatures.find(signature => imported.name === signature.name && parent.source.value === signature.from)) { loadableSpecifiers.push(local.name) } }, CallExpression(path) { if (!isValidIdentifier(path, loadableSpecifiers, lazyImportSpecifier)) return transformImport(path) }, 'ArrowFunctionExpression|FunctionExpression|ObjectMethod': path => { if (!hasLoadableComment(path)) return transformImport(path) }, }) }, }, }, } }) export default loadablePlugin ================================================ FILE: packages/babel-plugin/src/index.test.js ================================================ /* eslint-disable import/no-extraneous-dependencies */ import { transform } from '@babel/core' import plugin from '.' const testPlugin = (code, options) => { const result = transform(code, { plugins: [[plugin, options]], configFile: false, }) return result.code } describe('plugin', () => { describe('simple import', () => { it('should work with template literal', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }) it('should work with lazy if imported', () => { const result = testPlugin(` import { lazy } from '@loadable/component' lazy(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }) it('should not work with lazy if not imported', () => { const result = testPlugin(` import React, { lazy } from 'react' lazy(() => import(\`./ModA\`)) `) expect(result).toMatchInlineSnapshot(` "import React, { lazy } from 'react'; lazy(() => import(\`./ModA\`));" `) }) it('should work with renamed specifier by default', () => { const result = testPlugin(` import renamedLoadable from '@loadable/component' renamedLoadable(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }) it('should work with renamed lazy specifier', () => { const result = testPlugin(` import { lazy as renamedLazy } from '@loadable/component' renamedLazy(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }) it('should work with + concatenation', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import('./Mod' + 'A')) `) expect(result).toMatchSnapshot() }) it('should work with * in name', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import(\`./foo*\`)) `) expect(result).toMatchSnapshot() }) it('should transform path into "chunk-friendly" name', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import('../foo/bar')) `) expect(result).toMatchSnapshot() }) describe('with "webpackChunkName" comment', () => { it('should use it', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import(/* webpackChunkName: "ChunkA" */ './ModA')) `) expect(result).toMatchSnapshot() }) it('should use it even if comment is separated by ","', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import(/* webpackPrefetch: true, webpackChunkName: "ChunkA" */ './ModA')) `) expect(result).toMatchSnapshot() }) }) describe('without "webpackChunkName" comment', () => { it('should add it', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import('./ModA')) `) expect(result).toMatchSnapshot() }) }) describe('in a complex promise', () => { it('should work', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => timeout(import('./ModA'), 2000)) `) expect(result).toMatchSnapshot() }) }) }) describe('aggressive import', () => { it('should work with destructuration', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(({ foo }) => import(/* webpackChunkName: "Pages" */ \`./\${foo}\`)) `) expect(result).toMatchSnapshot() }) describe('with "webpackChunkName"', () => { it('should replace it', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(props => import(/* webpackChunkName: "Pages" */ \`./\${props.foo}\`)) `) expect(result).toMatchSnapshot() }) it('should keep it', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(props => import(/* webpackChunkName: "pages/[request]" */ \`./pages/\${props.path}\`)) `) expect(result).toMatchSnapshot() expect(result).toEqual( expect.stringContaining('return "pages/" + props.path.replace'), ) expect(result).toEqual( expect.stringContaining('/* webpackChunkName: "pages/[request]"'), ) }) }) describe('without "webpackChunkName"', () => { it('should support simple request', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(props => import(\`./\${props.foo}\`)) `) expect(result).toMatchSnapshot() }) it('should support complex request', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(props => import(\`./dir/\${props.foo}/test\`)) `) expect(result).toMatchSnapshot() }) it('should support destructuring', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(({ foo }) => import(\`./dir/\${foo}/test\`)) `) expect(result).toMatchSnapshot() }) }) }) describe('loadable.lib', () => { it('should be transpiled too', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable.lib(() => import('moment')) `) expect(result).toMatchSnapshot() }) }) describe('custom signatures', () => { it('(default) should support old named import', () => { const result = testPlugin(` import loadable from './loadable-utils' loadable(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }); it('should match simple default import', () => { const result = testPlugin(` import loadable from '@loadable/component' loadable(() => import(\`./ModA\`)) `, { signatures: [{ name: 'default', from: '@loadable/component' }]}) expect(result).toMatchSnapshot() }) it('should match renamed default import', () => { const result = testPlugin(` import renamedLoadable from '@loadable/component' renamedLoadable(() => import(\`./ModA\`)) `, { signatures: [{ name: 'default', from: '@loadable/component' }]}) expect(result).toMatchSnapshot() }) it('should match custom default signature', () => { const result = testPlugin(` import myLoadable from 'myLoadablePackage' myLoadable(() => import(\`./ModA\`)) `, { signatures: [{ name: 'default', from: 'myLoadablePackage' }]}) expect(result).toMatchSnapshot() }) it('should match custom named signature', () => { const result = testPlugin(` import { myLoadable } from 'myLoadablePackage' myLoadable(() => import(\`./ModA\`)) `, { signatures: [{ name: 'myLoadable', from: 'myLoadablePackage' }]}) expect(result).toMatchSnapshot() }) it('named signature should not match default import', () => { const result = testPlugin(` import myLoadable from 'myLoadablePackage' myLoadable(() => import(\`./ModA\`)) `, { signatures: [{ name: 'myLoadable', from: 'myLoadablePackage' }]}) expect(result).toMatchSnapshot() }) it('should not match on undeclared specifiers', () => { const result = testPlugin(` import myLoadable from 'myLoadablePackage' myLoadable(() => import(\`./ModA\`)) `) expect(result).toMatchSnapshot() }) }) describe('Magic comment', () => { it('should transpile shortand properties', () => { const result = testPlugin(` const obj = { /* #__LOADABLE__ */ load() { return import('moment') } } `) expect(result).toMatchSnapshot() }) it('should transpile arrow functions', () => { const result = testPlugin(` const load = /* #__LOADABLE__ */ () => import('moment') `) expect(result).toMatchSnapshot() }) it('should transpile function expression', () => { const result = testPlugin(` const load = /* #__LOADABLE__ */ function () { return import('moment') } `) expect(result).toMatchSnapshot() }) it('should remove only needed comments', () => { const result = testPlugin(` const load = /* #__LOADABLE__ */ /* IMPORTANT! */ () => import('moment') `) expect(result).toMatchSnapshot() }) }) }) ================================================ FILE: packages/babel-plugin/src/properties/chunkName.js ================================================ import vm from 'vm' import { getImportArg } from '../util' const JS_PATH_REGEXP = /^[./]+|(\.js$)/g const MATCH_LEFT_HYPHENS_REPLACE_REGEX = /^-/g // https://github.com/webpack/webpack/blob/master/lib/Template.js const WEBPACK_CHUNK_NAME_REGEXP = /webpackChunkName/ const WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g const WEBPACK_MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g function readWebpackCommentValues(str) { try { const values = vm.runInNewContext(`(function(){return {${str}};})()`) return values } catch (e) { throw Error(`compilation error while processing: /*${str}*/: ${e.message}`) } } function writeWebpackCommentValues(values) { try { const str = Object.keys(values) .map(key => `${key}: ${JSON.stringify(values[key])}`) .join(', ') return ` ${str} ` } catch (e) { throw Error( `compilation error while processing: /*${values}*/: ${e.message}`, ) } } function getChunkNameComment(importArg) { if (!importArg.has('leadingComments')) return null return importArg .get('leadingComments') .find(comment => comment.node.value.match(WEBPACK_CHUNK_NAME_REGEXP)) } function getRawChunkNameFromCommments(importArg) { const chunkNameComment = getChunkNameComment(importArg) if (!chunkNameComment) return null return readWebpackCommentValues(chunkNameComment.node.value) } function moduleToChunk(str) { if (typeof str !== 'string') return '' return str .replace(JS_PATH_REGEXP, '') .replace(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX, '-') .replace(WEBPACK_MATCH_PADDED_HYPHENS_REPLACE_REGEX, '') } function replaceQuasi(str, stripLeftHyphen) { if (!str) return '' const result = str.replace(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX, '-') if (!stripLeftHyphen) return result return result.replace(MATCH_LEFT_HYPHENS_REPLACE_REGEX, '') } export default function chunkNameProperty({ types: t }) { function transformQuasi(quasi, first, single) { return t.templateElement( { raw: single ? moduleToChunk(quasi.value.raw) : replaceQuasi(quasi.value.raw, first), cooked: single ? moduleToChunk(quasi.value.cooked) : replaceQuasi(quasi.value.cooked, first), }, quasi.tail, ) } function sanitizeChunkNameTemplateLiteral(node) { return t.callExpression(t.memberExpression(node, t.identifier('replace')), [ t.regExpLiteral(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX.source, 'g'), t.stringLiteral('-'), ]) } function combineExpressions(node) { const { expressions } = node const { length } = expressions if (length === 1) { return expressions[0] } return expressions .slice(1) .reduce((r, p) => t.binaryExpression('+', r, p), expressions[0]) } function generateChunkNameNode(callPath, prefix) { const importArg = getImportArg(callPath) if (importArg.isTemplateLiteral()) { return prefix ? t.binaryExpression( '+', t.stringLiteral(prefix), sanitizeChunkNameTemplateLiteral( combineExpressions(importArg.node), ), ) : t.templateLiteral( importArg.node.quasis.map((quasi, index) => transformQuasi( quasi, index === 0, importArg.node.quasis.length === 1, ), ), importArg.node.expressions, ) } return t.stringLiteral(moduleToChunk(importArg.node.value)) } function getExistingChunkNameComment(callPath) { const importArg = getImportArg(callPath) const values = getRawChunkNameFromCommments(importArg) return values } function isAgressiveImport(callPath) { const importArg = getImportArg(callPath) return ( importArg.isTemplateLiteral() && importArg.node.expressions.length > 0 ) } function addOrReplaceChunkNameComment(callPath, values) { const importArg = getImportArg(callPath) const chunkNameComment = getChunkNameComment(importArg) if (chunkNameComment) { chunkNameComment.remove() } importArg.addComment('leading', writeWebpackCommentValues(values)) } function chunkNameFromTemplateLiteral(node) { const [q1] = node.quasis const v1 = q1 ? q1.value.cooked : '' if (!node.expressions.length) return v1 return `${v1}[request]` } function getChunkNamePrefix(chunkName) { if (typeof chunkName !== 'string') return '' const match = chunkName.match(/(.+?)\[(request|index)\]$/) return match ? match[1] : '' } function replaceChunkName(callPath) { const agressiveImport = isAgressiveImport(callPath) const values = getExistingChunkNameComment(callPath) let { webpackChunkName } = values || {} if (!agressiveImport && values) { addOrReplaceChunkNameComment(callPath, values) return t.stringLiteral(webpackChunkName) } let chunkNameNode = generateChunkNameNode( callPath, getChunkNamePrefix(webpackChunkName), ) if (t.isTemplateLiteral(chunkNameNode)) { webpackChunkName = chunkNameFromTemplateLiteral(chunkNameNode) chunkNameNode = sanitizeChunkNameTemplateLiteral(chunkNameNode) } else if (t.isStringLiteral(chunkNameNode)) { webpackChunkName = chunkNameNode.value } addOrReplaceChunkNameComment(callPath, { ...values, webpackChunkName }) return chunkNameNode } return ({ callPath, funcPath }) => { const chunkName = replaceChunkName(callPath) return t.objectMethod( 'method', t.identifier('chunkName'), funcPath.node.params, t.blockStatement([t.returnStatement(chunkName)]), ) } } ================================================ FILE: packages/babel-plugin/src/properties/importAsync.js ================================================ export default function requireAsyncProperty({ types: t }) { function getFunc(funcPath) { if (funcPath.isObjectMethod()) { const { params, body, async } = funcPath.node return t.arrowFunctionExpression(params, body, async) } return funcPath.node } return ({ funcPath }) => t.objectProperty(t.identifier('importAsync'), getFunc(funcPath)) } ================================================ FILE: packages/babel-plugin/src/properties/isReady.js ================================================ export default function isReadyProperty({ types: t, template }) { const statements = template.ast(` const key=this.resolve(props) if (this.resolved[key] !== true) { return false } if (typeof __webpack_modules__ !== 'undefined') { return !!(__webpack_modules__[key]) } return false `) return () => t.objectMethod( 'method', t.identifier('isReady'), [t.identifier('props')], t.blockStatement(statements), ) } ================================================ FILE: packages/babel-plugin/src/properties/requireAsync.js ================================================ export default function requireAsyncProperty({ types: t, template }) { const tracking = template.ast(` const key = this.resolve(props) this.resolved[key] = false return this.importAsync(props).then(resolved => { this.resolved[key] = true return resolved; }); `) return () => t.objectMethod( 'method', t.identifier('requireAsync'), [t.identifier('props')], t.blockStatement(tracking), ) } ================================================ FILE: packages/babel-plugin/src/properties/requireSync.js ================================================ export default function requireSyncProperty({ types: t, template }) { const statements = template.ast(` const id = this.resolve(props) if (typeof __webpack_require__ !== 'undefined') { return __webpack_require__(id) } return eval('module.require')(id) `) return () => t.objectMethod( 'method', t.identifier('requireSync'), [t.identifier('props')], t.blockStatement(statements), ) } ================================================ FILE: packages/babel-plugin/src/properties/resolve.js ================================================ import { getImportArg } from '../util' export default function resolveProperty({ types: t, template }) { const buildStatements = template` if (require.resolveWeak) { return require.resolveWeak(ID) } return eval('require.resolve')(ID) ` function getCallValue(callPath) { const importArg = getImportArg(callPath) if (importArg.isTemplateLiteral()) { return t.templateLiteral( importArg.node.quasis, importArg.node.expressions, ) } if (importArg.isBinaryExpression()) { return t.BinaryExpression( importArg.node.operator, importArg.node.left, importArg.node.right, ) } return t.stringLiteral(importArg.node.value) } return ({ callPath, funcPath }) => t.objectMethod( 'method', t.identifier('resolve'), funcPath.node.params, t.blockStatement(buildStatements({ ID: getCallValue(callPath) })), ) } ================================================ FILE: packages/babel-plugin/src/properties/state.js ================================================ export default function requireAsyncProperty({ types: t }) { return () => t.objectProperty(t.identifier('resolved'), t.objectExpression([])) } ================================================ FILE: packages/babel-plugin/src/util.js ================================================ /* eslint-disable import/prefer-default-export */ export function getImportArg(callPath) { return callPath.get('arguments.0') } ================================================ FILE: packages/codemod/.npmignore ================================================ transforms/__testfixtures__ transforms/__tests__ ================================================ FILE: packages/codemod/CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [5.13.2](https://github.com/gregberge/loadable-components/compare/v5.13.1...v5.13.2) (2020-09-14) **Note:** Version bump only for package loadable-codemod ## [5.13.1](https://github.com/gregberge/loadable-components/compare/v5.13.0...v5.13.1) (2020-07-02) ### Bug Fixes * expose used chunkNames from a server. Fixes [#587](https://github.com/gregberge/loadable-components/issues/587) ([831aec0](https://github.com/gregberge/loadable-components/commit/831aec03154ab16007db0d78fbf3559583c000fe)) # [5.13.0](https://github.com/gregberge/loadable-components/compare/v5.12.0...v5.13.0) (2020-06-29) **Note:** Version bump only for package loadable-codemod # [5.12.0](https://github.com/gregberge/loadable-components/compare/v5.11.0...v5.12.0) (2020-01-09) ### Features * add codemods to migrate from react-loadable ([#463](https://github.com/gregberge/loadable-components/issues/463)) ([a82d5ad](https://github.com/gregberge/loadable-components/commit/a82d5ad1e17cd64d3579aa207abfc18346ff0107)) ================================================ FILE: packages/codemod/README.md ================================================ # @loadable/codemod This package is a collection of codemod that can be used to help making big changes easier to a project, for example: migrating from `react-loadable` to `@loadable/component` ## Notes about `react-loadable-to-loadable-component` transform `react-loadable-to-loadable-component` transform will help codemod all of your `Loadable()` declaration to `loadable()` with mostly equivalent params, barring some behavior that do not exist in `@loadable/component` such as `Loadable.Map()`, `timeout`, `delay`, etc. After running the codemod, you will still need to update some of your code manually, namely: 1. Using `loadableReady` to hydrate your app on the client side. 2. Updating your webpack configuration to use `@loadable` 3. Updating your server side rendering code to use `ChunkExtractor` ================================================ FILE: packages/codemod/bin/main.js ================================================ #!/usr/bin/env node /* eslint-disable no-console */ const yargs = require('yargs') const execa = require('execa') const path = require('path') const fs = require('fs') const chalk = require('chalk') const CodemodError = require('./utils/CodemodError') const jscodeshiftExecutable = require.resolve('.bin/jscodeshift') const transformsDir = path.resolve(__dirname, '../transforms') const { argv } = yargs try { const selectedCodemod = argv._[0] const directoryToApplyTo = argv._[1] if (!selectedCodemod || !directoryToApplyTo) { throw new CodemodError({ type: 'Invalid params', }) } const availableTransforms = fs .readdirSync(transformsDir) .filter(v => v !== '__tests__' && v !== '__testfixtures__') .map(v => v.replace('.js', '')) if (!availableTransforms.some(t => t === selectedCodemod)) { throw new CodemodError({ type: 'Unrecognised transform', payload: selectedCodemod, }) } const result = execa.commandSync( `${jscodeshiftExecutable} -t ${transformsDir}/${selectedCodemod}.js ${directoryToApplyTo}`, { stdio: 'inherit', stripEof: false, }, ) if (result.error) { throw result.error } } catch (err) { if (err.type === 'Invalid params') { console.error(chalk.red('Invalid params passed!')) console.error( chalk.red( 'loadable-codemod requires 2 params to be passed, the name of the codemod, and a directory to apply the codemod to.', ), ) console.error( chalk.red( 'Example: npx loadable-codemod react-loadable-to-loadable-component ./src/client', ), ) process.exit(1) } if (err.type === 'Unrecognised transform') { console.error(chalk.red(`Unrecognised transform passed: '${err.payload}'`)) process.exit(2) } // For other errors, just re-throw it throw err } ================================================ FILE: packages/codemod/bin/utils/CodemodError.js ================================================ class CodemodError extends Error { constructor(args) { super(args) this.type = args.type this.payload = args.payload } } module.exports = CodemodError ================================================ FILE: packages/codemod/package.json ================================================ { "name": "loadable-codemod", "description": "Various codemods related to @loadable/components for easier migration/upgrades.", "version": "5.13.2", "repository": "git@github.com:gregberge/loadable-components.git", "author": "Jacky Efendi ", "bin": { "loadable-codemod": "./bin/main.js" }, "publishConfig": { "access": "public" }, "keywords": [ "react", "ssr", "webpack", "code-splitting", "react-router", "server-side-rendering", "dynamic-import", "react-loadable", "react-async-components", "codemod" ], "engines": { "node": ">=8" }, "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", "jscodeshift": "0.7.0", "yargs": "^15.1.0" } } ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_arrow-no-params.input.js ================================================ /* eslint-disable */ import Loadable from 'react-loadable' const CustomLinkLoadable = Loadable({ loader: () => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), loading: () =>
loading...
, delay: 0, }) ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_arrow-no-params.output.js ================================================ /* eslint-disable */ import loadable from '@loadable/component' const CustomLinkLoadable = loadable(() => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), { fallback: (() =>
loading...
)(), }) ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_arrow-w-params.input.js ================================================ /* eslint-disable */ import Loadable from 'react-loadable' const CustomLinkLoadable = Loadable({ loader: () => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), loading: (props) => { if (props.error || props.timedOut) { throw new Error('Failed to load custom link chunk') } else if (props.loading) { return
loading...
; } }, delay: 0, }) ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_arrow-w-params.output.js ================================================ /* eslint-disable */ import loadable from '@loadable/component' const CustomLinkLoadable = loadable(() => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), { fallback: (props => { if (props.error || props.timedOut) { throw new Error('Failed to load custom link chunk') } else if (props.loading) { return
loading...
; } })({ pastDelay: true, error: false, timedOut: false, }), }) ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_expr.input.js ================================================ /* eslint-disable */ import Loadable from 'react-loadable' const Loading = props => { if (props.error || props.timedOut) { throw new Error('Failed to load custom link chunk') } else { return null } } const CustomLinkLoadable = Loadable({ loader: () => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), loading: Loading, delay: 0, }) ================================================ FILE: packages/codemod/transforms/__testfixtures__/react-loadable-to-loadable-component_expr.output.js ================================================ /* eslint-disable */ import loadable from '@loadable/component' const Loading = props => { if (props.error || props.timedOut) { throw new Error('Failed to load custom link chunk') } else { return null } } const CustomLinkLoadable = loadable(() => import(/* webpackChunkName: "custom-link" */ '@components/CustomLink/Link'), { fallback: Loading({ pastDelay: true, error: false, timedOut: false, }), }) ================================================ FILE: packages/codemod/transforms/__tests__/react-loadable-to-loadable-component-test.js ================================================ jest.autoMockOff() const { defineTest } = require('jscodeshift/dist/testUtils') defineTest( __dirname, 'react-loadable-to-loadable-component', null, 'react-loadable-to-loadable-component_expr', ) defineTest( __dirname, 'react-loadable-to-loadable-component', null, 'react-loadable-to-loadable-component_arrow-no-params', ) defineTest( __dirname, 'react-loadable-to-loadable-component', null, 'react-loadable-to-loadable-component_arrow-w-params', ) ================================================ FILE: packages/codemod/transforms/react-loadable-to-loadable-component.js ================================================ /* eslint-disable no-param-reassign */ /* eslint-disable no-console */ const chalk = require('chalk') const invokeWithMockedUpProp = (jscodeshift, file, prop) => { // We invoke the function previously passed as `loading` to react-loadable with this props // { // pastDelay: true, // error: false, // timedOut: false, // } const j = jscodeshift const defaultPropsObjProperties = [] defaultPropsObjProperties.push( j.objectProperty(j.identifier('pastDelay'), j.booleanLiteral(true)), ) defaultPropsObjProperties.push( j.objectProperty(j.identifier('error'), j.booleanLiteral(false)), ) defaultPropsObjProperties.push( j.objectProperty(j.identifier('timedOut'), j.booleanLiteral(false)), ) const defaultPropsObj = j.objectExpression(defaultPropsObjProperties) const callExpr = j.callExpression(prop.value, [defaultPropsObj]) prop.value = callExpr console.warn( chalk.yellow( `[WARN] '${file.path}' has some react-loadable specific logic in it. We could not codemod while keeping all the behaviors the same. Please check this file manually.`, ), ) } module.exports = (file, api) => { const { source } = file const { jscodeshift: j } = api const root = j(source) // Rename `import Loadable from 'react-loadable';` to `import loadable from '@loadable/component'; root.find(j.ImportDeclaration).forEach(({ node }) => { if ( node.specifiers[0] && node.specifiers[0].local.name === 'Loadable' && node.source.value === 'react-loadable' ) { node.specifiers[0].local.name = 'loadable' node.source.value = '@loadable/component' } }) // Change Loadable({ ... }) invocation to loadable(() => {}, { ... }) invocation root .find(j.CallExpression, { callee: { name: 'Loadable' } }) .forEach(path => { const { node } = path const initialArgsProps = node.arguments[0].properties let loader // this will be a function returning a dynamic import promise // loop through the first argument (object) passed to `Loadable({ ... })` const newProps = initialArgsProps .map(prop => { if (prop.key.name === 'loader') { /** * In react-loadable, this is the function that returns a dynamic import * We'll keep it to `loader` variable for now, and remove it from the arg object */ loader = prop.value return undefined } if (prop.key.name === 'loading') { prop.key.name = 'fallback' // rename to fallback /** * react-loadable accepts a Function that returns JSX as the `loading` arg. * @loadable/component accepts a React.Element (what returned from React.createElement() calls) * */ if (prop.value.type === 'ArrowFunctionExpression') { // if it's an ArrowFunctionExpression like `() =>
loading...
`, if ( (prop.value.params && prop.value.params.length > 0) || prop.value.type === 'Identifier' ) { // If the function accept props, we can invoke it and pass it a mocked-up props to get the component to // a should-be-acceptable default state, while also logs out a warning. // { // pastDelay: true, // error: false, // timedOut: false, // } invokeWithMockedUpProp(j, file, prop) } else { // If the function doesn't accept any params, we can safely just invoke it directly // we can change it to `(() =>
loading...
)()` const callExpr = j.callExpression(prop.value, []) prop.value = callExpr } } else if (prop.value.type === 'Identifier') { // if it's an identifier like `Loading`, let's just invoke it with a mocked-up props invokeWithMockedUpProp(j, file, prop) } return prop } // for all other props, just remove them return undefined }) .filter(Boolean) // add the function that return a dynamic import we stored earlier as the first argument to `loadable()` call node.arguments.unshift(loader) node.arguments[1].properties = newProps node.callee.name = 'loadable' }) return root.toSource({ quote: 'single', trailingComma: true }) } module.exports.parser = 'babylon' ================================================ FILE: packages/component/.npmignore ================================================ src/ .* rollup.config.js ================================================ FILE: packages/component/.size-snapshot.json ================================================ { "dist/cjs/loadable.cjs.js": { "bundled": 16900, "minified": 7226, "gzipped": 2545 }, "dist/esm/loadable.esm.mjs": { "bundled": 16517, "minified": 6917, "gzipped": 2490, "treeshaked": { "rollup": { "code": 259, "import_statements": 259 }, "webpack": { "code": 5764 } } } } ================================================ FILE: packages/component/CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [5.16.7](https://github.com/gregberge/loadable-components/compare/v5.16.6...v5.16.7) (2025-05-18) **Note:** Version bump only for package @loadable/component ## [5.16.6](https://github.com/gregberge/loadable-components/compare/v5.16.5...v5.16.6) (2025-05-18) **Note:** Version bump only for package @loadable/component ## [5.16.4](https://github.com/gregberge/loadable-components/compare/v5.16.3...v5.16.4) (2024-04-20) ### Bug Fixes * correct esm configuration for loadable/server, fixes: [#999](https://github.com/gregberge/loadable-components/issues/999) ([#1004](https://github.com/gregberge/loadable-components/issues/1004)) ([114cea2](https://github.com/gregberge/loadable-components/commit/114cea2b61ef644d3b794a9b5f48df69f0f5400b)) ## [5.16.3](https://github.com/gregberge/loadable-components/compare/v5.16.2...v5.16.3) (2023-12-26) ### Bug Fixes * correct react-is for mjs export; remove isValidComponent check ([#991](https://github.com/gregberge/loadable-components/issues/991)) ([9d381c3](https://github.com/gregberge/loadable-components/commit/9d381c35b7fc1f8f9122caac25e8e255871ebab6)) ## [5.16.2](https://github.com/gregberge/loadable-components/compare/v5.16.1...v5.16.2) (2023-12-15) ### Bug Fixes * add esm exports to package.json and change esm bundle extension to .mjs to allow node.js to properly import esm version of package. ([#989](https://github.com/gregberge/loadable-components/issues/989)) ([e4a3718](https://github.com/gregberge/loadable-components/commit/e4a37188b804e6a5bc66f39c23c738006bc0e284)) ## [5.15.3](https://github.com/gregberge/loadable-components/compare/v5.15.2...v5.15.3) (2023-01-28) ### Bug Fixes * add React 17 and 18 to package dependencies, fixes [#718](https://github.com/gregberge/loadable-components/issues/718) ([66edc37](https://github.com/gregberge/loadable-components/commit/66edc37a731a8ec655deffd3ad454fd96e909ba3)) ## [5.15.2](https://github.com/gregberge/loadable-components/compare/v5.15.1...v5.15.2) (2021-12-12) ### Bug Fixes * loadAsync Loadable should copy statics ([#839](https://github.com/gregberge/loadable-components/issues/839)) ([9ff6693](https://github.com/gregberge/loadable-components/commit/9ff66939ee6fd622922f71128a30b5d3f43f63b0)) * use stable promises for load/preload/React ([#858](https://github.com/gregberge/loadable-components/issues/858)) ([45f2d91](https://github.com/gregberge/loadable-components/commit/45f2d9133c8234fec9cbe36e5a162a61f24e4aae)) # [5.15.0](https://github.com/gregberge/loadable-components/compare/v5.14.2...v5.15.0) (2021-05-08) ### Bug Fixes * add displayNames to generated components ([#731](https://github.com/gregberge/loadable-components/issues/731)) ([b640c82](https://github.com/gregberge/loadable-components/commit/b640c82a742ffbccc423439e2e205d1becdf5491)) ### Features * support multiple Webpack runtimes ([#701](https://github.com/gregberge/loadable-components/issues/701)) ([d351367](https://github.com/gregberge/loadable-components/commit/d3513679ed680e46967ca18555116c06e5a4b341)) ## [5.14.1](https://github.com/gregberge/loadable-components/compare/v5.14.0...v5.14.1) (2020-10-22) **Note:** Version bump only for package @loadable/component # [5.14.0](https://github.com/gregberge/loadable-components/compare/v5.13.2...v5.14.0) (2020-10-20) ### Bug Fixes * do not derive cache key if component is static, fixes [#629](https://github.com/gregberge/loadable-components/issues/629) ([#630](https://github.com/gregberge/loadable-components/issues/630)) ([b4151d8](https://github.com/gregberge/loadable-components/commit/b4151d85b3ba0f57e9fab48ec88f5e57e4d0b544)) ### Features * make packages webpack 5 compatible ([#638](https://github.com/gregberge/loadable-components/issues/638)) ([e882e4d](https://github.com/gregberge/loadable-components/commit/e882e4d812e714066eba19a11dd119193e7a9e01)) ## [5.13.2](https://github.com/gregberge/loadable-components/compare/v5.13.1...v5.13.2) (2020-09-14) ### Bug Fixes * Fixed lazy usage with Suspense and Error Boundary together ([#521](https://github.com/gregberge/loadable-components/issues/521)) ([42fbdd0](https://github.com/gregberge/loadable-components/commit/42fbdd0d552551b18ed0781383bb0073e1cd8640)) ## [5.13.1](https://github.com/gregberge/loadable-components/compare/v5.13.0...v5.13.1) (2020-07-02) ### Bug Fixes * expose used chunkNames from a server. Fixes [#587](https://github.com/gregberge/loadable-components/issues/587) ([831aec0](https://github.com/gregberge/loadable-components/commit/831aec03154ab16007db0d78fbf3559583c000fe)) # [5.13.0](https://github.com/gregberge/loadable-components/compare/v5.12.0...v5.13.0) (2020-06-29) ### Bug Fixes * allow webpack cache is ready only for initial chunks, fixes [#558](https://github.com/gregberge/loadable-components/issues/558) ([61f8b75](https://github.com/gregberge/loadable-components/commit/61f8b75b54612368c88807d73abb7dc7add720ad)) ### Features * add `resolveComponent` option ([a47d3d9](https://github.com/gregberge/loadable-components/commit/a47d3d9021ee6b12c1209bf41069dc133cb1fa7c)) # [5.12.0](https://github.com/gregberge/loadable-components/compare/v5.11.0...v5.12.0) (2020-01-09) ### Bug Fixes * apply loadable transformations before any other, fixes [#466](https://github.com/gregberge/loadable-components/issues/466) ([ac5ba45](https://github.com/gregberge/loadable-components/commit/ac5ba45862bad68b971a969e6e8713874add51a6)) ### Features * avoid synchronous loading on client if options.ssr is false ([#346](https://github.com/gregberge/loadable-components/issues/346)) ([338bf55](https://github.com/gregberge/loadable-components/commit/338bf555adc68986b12c8dd4e304875425119ca2)) # [5.11.0](https://github.com/smooth-code/loadable-components/compare/v5.10.3...v5.11.0) (2019-12-02) ### Bug Fixes * fix isReady problem ([#445](https://github.com/smooth-code/loadable-components/issues/445)) ([3024348](https://github.com/smooth-code/loadable-components/commit/30243482be917e89515d057e2368e7278e34696c)), closes [#400](https://github.com/smooth-code/loadable-components/issues/400) ## [5.10.3](https://github.com/smooth-code/loadable-components/compare/v5.10.2...v5.10.3) (2019-09-24) ### Bug Fixes * support IE 11 without polyfill ([#416](https://github.com/smooth-code/loadable-components/issues/416)) ([80ee809](https://github.com/smooth-code/loadable-components/commit/80ee809)), closes [#397](https://github.com/smooth-code/loadable-components/issues/397) ## [5.10.2](https://github.com/smooth-code/loadable-components/compare/v5.10.1...v5.10.2) (2019-07-15) ### Bug Fixes * use === instead of Object.is ([c88cd82](https://github.com/smooth-code/loadable-components/commit/c88cd82)), closes [#371](https://github.com/smooth-code/loadable-components/issues/371) ## [5.10.1](https://github.com/smooth-code/loadable-components/compare/v5.10.0...v5.10.1) (2019-05-14) ### Bug Fixes * add @babel/preset-env in rollup config ([#336](https://github.com/smooth-code/loadable-components/issues/336)) ([8b50c94](https://github.com/smooth-code/loadable-components/commit/8b50c94)), closes [#335](https://github.com/smooth-code/loadable-components/issues/335) # [5.10.0](https://github.com/smooth-code/loadable-components/compare/v5.9.0...v5.10.0) (2019-05-13) ### Features * add `load` method that returns a Promise ([#329](https://github.com/smooth-code/loadable-components/issues/329)) ([a10a9d5](https://github.com/smooth-code/loadable-components/commit/a10a9d5)), closes [#226](https://github.com/smooth-code/loadable-components/issues/226) * support reactive dynamic loadable ([#330](https://github.com/smooth-code/loadable-components/issues/330)) ([d65c5bb](https://github.com/smooth-code/loadable-components/commit/d65c5bb)), closes [#284](https://github.com/smooth-code/loadable-components/issues/284) ### Performance Improvements * optimize rollup config ([c94760b](https://github.com/smooth-code/loadable-components/commit/c94760b)) # [5.9.0](https://github.com/smooth-code/loadable-components/compare/v5.8.0...v5.9.0) (2019-04-23) ### Features * support multiple react apps ([#317](https://github.com/smooth-code/loadable-components/issues/317)) ([dc54050](https://github.com/smooth-code/loadable-components/commit/dc54050)), closes [#311](https://github.com/smooth-code/loadable-components/issues/311) # [5.7.0](https://github.com/smooth-code/loadable-components/compare/v5.6.1...v5.7.0) (2019-03-14) ### Bug Fixes * **component:** fix warning message about babel ([#255](https://github.com/smooth-code/loadable-components/issues/255)) ([7cb68a1](https://github.com/smooth-code/loadable-components/commit/7cb68a1)), closes [#253](https://github.com/smooth-code/loadable-components/issues/253) ### Features * use inline JSON to enabling CSP without `unsafe-inline` ([05e5500](https://github.com/smooth-code/loadable-components/commit/05e5500)) ## [5.6.1](https://github.com/smooth-code/loadable-components/compare/v5.6.0...v5.6.1) (2019-02-25) ### Bug Fixes * **component:** better ES Modules handling ([#228](https://github.com/smooth-code/loadable-components/issues/228)) ([3628363](https://github.com/smooth-code/loadable-components/commit/3628363)) * **suspense:** fix suspense mode in React v16.8+ ([#251](https://github.com/smooth-code/loadable-components/issues/251)) ([d04e1c9](https://github.com/smooth-code/loadable-components/commit/d04e1c9)) # [5.6.0](https://github.com/smooth-code/loadable-components/compare/v5.5.0...v5.6.0) (2019-02-05) ### Features * **component:** add preload method ([#224](https://github.com/smooth-code/loadable-components/issues/224)) ([4a67ace](https://github.com/smooth-code/loadable-components/commit/4a67ace)), closes [#196](https://github.com/smooth-code/loadable-components/issues/196) * **server:** add option to disable SSR ([#223](https://github.com/smooth-code/loadable-components/issues/223)) ([4cab4f9](https://github.com/smooth-code/loadable-components/commit/4cab4f9)), closes [#195](https://github.com/smooth-code/loadable-components/issues/195) # [5.5.0](https://github.com/smooth-code/loadable-components/compare/v5.4.0...v5.5.0) (2019-01-22) **Note:** Version bump only for package @loadable/component ## [5.2.2](https://github.com/smooth-code/loadable-components/compare/v5.2.1...v5.2.2) (2018-12-12) ### Bug Fixes * ensure that component is mounted before calling `setState` ([#184](https://github.com/smooth-code/loadable-components/issues/184)) ([fe0f47f](https://github.com/smooth-code/loadable-components/commit/fe0f47f)), closes [#180](https://github.com/smooth-code/loadable-components/issues/180) ## [5.2.1](https://github.com/smooth-code/loadable-components/compare/v5.2.0...v5.2.1) (2018-11-27) ### Bug Fixes * upgrade hoist-non-react-statics@3.2.0 ([122b1ce](https://github.com/smooth-code/loadable-components/commit/122b1ce)) ## [5.1.2](https://github.com/smooth-code/loadable-components/compare/v5.1.1...v5.1.2) (2018-11-13) ### Bug Fixes * fix ref handler in `loadable.lib` ([da05d87](https://github.com/smooth-code/loadable-components/commit/da05d87)) # [5.0.0](https://github.com/smooth-code/loadable-components/compare/v4.0.5...v5.0.0) (2018-11-10) ### Bug Fixes * fix loadableReady ([59693bb](https://github.com/smooth-code/loadable-components/commit/59693bb)) ### Features * improve SSR support ([eb1cfe8](https://github.com/smooth-code/loadable-components/commit/eb1cfe8)) ### BREAKING CHANGES * - SSR has been rewritten from scratch, if you use it, please follow the new guide. - Prefetch component and prefetch functions have been removed, please use `webpackPrefetch` instead. ## [4.0.2](https://github.com/smooth-code/loadable-components/compare/v4.0.1...v4.0.2) (2018-10-31) ### Bug Fixes * **component:** fix lazy usage ([d711ee0](https://github.com/smooth-code/loadable-components/commit/d711ee0)) ## [4.0.1](https://github.com/smooth-code/loadable-components/compare/v4.0.0...v4.0.1) (2018-10-30) ### Bug Fixes * **component:** do not call ref several times ([8cf3190](https://github.com/smooth-code/loadable-components/commit/8cf3190)) # [4.0.0](https://github.com/smooth-code/loadable-components/compare/v3.0.2...v4.0.0) (2018-10-30) ### Features * add new loadable.lib, change API ([94b2e87](https://github.com/smooth-code/loadable-components/commit/94b2e87)) ### BREAKING CHANGES * - `ErrorComponent` is ignored, please use Error Boundaries to handle errors. - `lazy` is no longer exported - `LoadingComponent` is replaced by `fallback` option - `ref` are now forwarded ## [3.0.2](https://github.com/smooth-code/loadable-components/compare/v3.0.1...v3.0.2) (2018-10-30) ### Bug Fixes * **component:** fix loadComponent (typo) ([a410cb2](https://github.com/smooth-code/loadable-components/commit/a410cb2)) ## [3.0.1](https://github.com/smooth-code/loadable-components/compare/v3.0.0...v3.0.1) (2018-10-30) ### Bug Fixes * **component:** fix loadComponents ([bd2220c](https://github.com/smooth-code/loadable-components/commit/bd2220c)) # [3.0.0](https://github.com/smooth-code/loadable-components/compare/v2.2.3...v3.0.0) (2018-10-29) ### Features * welcome loadable ([4dffad7](https://github.com/smooth-code/loadable-components/commit/4dffad7)) ### BREAKING CHANGES * API has completely changed, see documentation. ================================================ FILE: packages/component/README.md ================================================ # @loadable/component Enable Code Splitting in your React application. ## Install ``` npm install @loadable/component ``` ## Documentation 👉 [See full documentation](https://loadable-components.com/) ## License MIT ================================================ FILE: packages/component/package.json ================================================ { "name": "@loadable/component", "description": "React code splitting made easy.", "version": "5.16.7", "main": "./dist/cjs/loadable.cjs.js", "module": "./dist/esm/loadable.esm.mjs", "exports": { ".": { "require": "./dist/cjs/loadable.cjs.js", "import": "./dist/esm/loadable.esm.mjs", "default": "./dist/cjs/loadable.cjs.js" } }, "repository": "git@github.com:gregberge/loadable-components.git", "author": "Greg Bergé ", "publishConfig": { "access": "public" }, "keywords": [ "react", "ssr", "webpack", "code-splitting", "react-router", "server-side-rendering", "dynamic-import", "react-loadable", "react-async-components" ], "engines": { "node": ">=8" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" }, "license": "MIT", "scripts": { "prebuild": "shx rm -rf dist", "build": "cross-env rollup -c && yarn create-cjs-package-json", "create-cjs-package-json": "echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", "prepublishOnly": "yarn run build" }, "peerDependencies": { "react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "dependencies": { "@babel/runtime": "^7.12.18", "hoist-non-react-statics": "^3.3.1", "react-is": "^16.12.0" } } ================================================ FILE: packages/component/rollup.config.js ================================================ /* eslint-disable import/no-extraneous-dependencies */ import nodeResolve from 'rollup-plugin-node-resolve' import babel from 'rollup-plugin-babel' import replace from 'rollup-plugin-replace' import commonjs from 'rollup-plugin-commonjs' import { terser } from 'rollup-plugin-terser' import pkg from './package.json' const input = 'src/index.js' const name = 'loadable' const globals = { react: 'React', 'hoist-non-react-statics': 'hoistNonReactStatics', } const external = id => !id.startsWith('.') && !id.startsWith('/') const getBabelOptions = ({ useESModules }) => ({ exclude: '**/node_modules/**', runtimeHelpers: true, presets: [ ['@babel/preset-env', { loose: true }], ['@babel/preset-react', { useBuiltIns: true }], ], plugins: [ '@babel/plugin-proposal-class-properties', 'babel-plugin-annotate-pure-calls', ['@babel/plugin-transform-runtime', { useESModules }], ], }) export default [ // umd { input, output: { file: `dist/loadable.js`, format: 'umd', name, globals, exports: 'named', sourcemap: false, }, external: Object.keys(globals), plugins: [ babel(getBabelOptions({ useESModules: true })), nodeResolve(), commonjs(), replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), ], }, // min { input, output: { file: 'dist/loadable.min.js', format: 'umd', name, globals, exports: 'named', sourcemap: false, }, external: Object.keys(globals), plugins: [ babel(getBabelOptions({ useESModules: true })), nodeResolve(), commonjs(), replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), terser(), ], }, // cjs { input, output: { file: pkg.main, format: 'cjs', exports: 'named' }, external, plugins: [babel(getBabelOptions({ useESModules: false }))], }, // esm { input, output: { file: pkg.module, format: 'esm' }, external, plugins: [babel(getBabelOptions({ useESModules: true }))], }, ] ================================================ FILE: packages/component/src/Context.js ================================================ import React from 'react' export default React.createContext() ================================================ FILE: packages/component/src/createLoadable.js ================================================ /* eslint-disable no-use-before-define, react/no-multi-comp, no-underscore-dangle */ import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import { invariant } from './util' import Context from './Context' import { LOADABLE_SHARED } from './shared' const STATUS_PENDING = 'PENDING' const STATUS_RESOLVED = 'RESOLVED' const STATUS_REJECTED = 'REJECTED' function resolveConstructor(ctor) { if (typeof ctor === 'function') { return { requireAsync: ctor, resolve() { return undefined }, chunkName() { return undefined }, } } return ctor } const withChunkExtractor = Component => { const LoadableWithChunkExtractor = props => ( {extractor => } ) if (Component.displayName) { LoadableWithChunkExtractor.displayName = `${Component.displayName}WithChunkExtractor` } return LoadableWithChunkExtractor } const identity = v => v function createLoadable({ defaultResolveComponent = identity, render, onLoad, }) { function loadable(loadableConstructor, options = {}) { const ctor = resolveConstructor(loadableConstructor) const cache = {} /** * Cachekey represents the component to be loaded * if key changes - component has to be reloaded * @param props * @returns {null|Component} */ function getCacheKey(props) { if (options.cacheKey) { return options.cacheKey(props) } if (ctor.resolve) { return ctor.resolve(props) } return 'static' } /** * Resolves loaded `module` to a specific `Component * @param module * @param props * @param Loadable * @returns Component */ function resolve(module, props, Loadable) { const Component = options.resolveComponent ? options.resolveComponent(module, props) : defaultResolveComponent(module) // FIXME: suppressed due to https://github.com/gregberge/loadable-components/issues/990 // if (options.resolveComponent && !ReactIs.isValidElementType(Component)) { // throw new Error( // `resolveComponent returned something that is not a React component!`, // ) // } hoistNonReactStatics(Loadable, Component, { preload: true, }) return Component } const cachedLoad = props => { const cacheKey = getCacheKey(props) let promise = cache[cacheKey] if (!promise || promise.status === STATUS_REJECTED) { promise = ctor.requireAsync(props) promise.status = STATUS_PENDING cache[cacheKey] = promise promise.then( () => { promise.status = STATUS_RESOLVED }, error => { console.error( 'loadable-components: failed to asynchronously load component', { fileName: ctor.resolve(props), chunkName: ctor.chunkName(props), error: error ? error.message : error, }, ) promise.status = STATUS_REJECTED }, ) } return promise } class InnerLoadable extends React.Component { static getDerivedStateFromProps(props, state) { const cacheKey = getCacheKey(props) return { ...state, cacheKey, // change of a key triggers loading state automatically loading: state.loading || state.cacheKey !== cacheKey, } } constructor(props) { super(props) this.state = { result: null, error: null, loading: true, cacheKey: getCacheKey(props), } invariant( !props.__chunkExtractor || ctor.requireSync, 'SSR requires `@loadable/babel-plugin`, please install it', ) // Server-side if (props.__chunkExtractor) { // This module has been marked with no SSR if (options.ssr === false) { return } // We run load function, we assume that it won't fail and that it // triggers a synchronous loading of the module ctor.requireAsync(props).catch(() => null) // So we can require now the module synchronously this.loadSync() props.__chunkExtractor.addChunk(ctor.chunkName(props)) return } // Client-side with `isReady` method present (SSR probably) // If module is already loaded, we use a synchronous loading // Only perform this synchronous loading if the component has not // been marked with no SSR, else we risk hydration mismatches if ( options.ssr !== false && // is ready - was loaded in this session ((ctor.isReady && ctor.isReady(props)) || // is ready - was loaded during SSR process (ctor.chunkName && LOADABLE_SHARED.initialChunks[ctor.chunkName(props)])) ) { this.loadSync() } } componentDidMount() { this.mounted = true // retrieve loading promise from a global cache const cachedPromise = this.getCache() // if promise exists, but rejected - clear cache if (cachedPromise && cachedPromise.status === STATUS_REJECTED) { this.setCache() } // component might be resolved synchronously in the constructor if (this.state.loading) { this.loadAsync() } } componentDidUpdate(prevProps, prevState) { // Component has to be reloaded on cacheKey change if (prevState.cacheKey !== this.state.cacheKey) { this.loadAsync() } } componentWillUnmount() { this.mounted = false } safeSetState(nextState, callback) { if (this.mounted) { this.setState(nextState, callback) } } /** * returns a cache key for the current props * @returns {Component|string} */ getCacheKey() { return getCacheKey(this.props) } /** * access the persistent cache */ getCache() { return cache[this.getCacheKey()] } /** * sets the cache value. If called without value sets it as undefined */ setCache(value = undefined) { cache[this.getCacheKey()] = value } triggerOnLoad() { if (onLoad) { setTimeout(() => { onLoad(this.state.result, this.props) }) } } /** * Synchronously loads component * target module is expected to already exists in the module cache * or be capable to resolve synchronously (webpack target=node) */ loadSync() { // load sync is expecting component to be in the "loading" state already // sounds weird, but loading=true is the initial state of InnerLoadable if (!this.state.loading) return try { const loadedModule = ctor.requireSync(this.props) const result = resolve(loadedModule, this.props, Loadable) this.state.result = result this.state.loading = false } catch (error) { console.error( 'loadable-components: failed to synchronously load component, which expected to be available', { fileName: ctor.resolve(this.props), chunkName: ctor.chunkName(this.props), error: error ? error.message : error, }, ) this.state.error = error } } /** * Asynchronously loads a component. */ loadAsync() { const promise = this.resolveAsync() promise .then(loadedModule => { const result = resolve(loadedModule, this.props, Loadable) this.safeSetState( { result, loading: false, }, () => this.triggerOnLoad(), ) }) .catch(error => this.safeSetState({ error, loading: false })) return promise } /** * Asynchronously resolves(not loads) a component. * Note - this function does not change the state */ resolveAsync() { const { __chunkExtractor, forwardedRef, ...props } = this.props return cachedLoad(props) } render() { const { forwardedRef, fallback: propFallback, __chunkExtractor, ...props } = this.props const { error, loading, result } = this.state if (options.suspense) { const cachedPromise = this.getCache() || this.loadAsync() if (cachedPromise.status === STATUS_PENDING) { throw this.loadAsync() } } if (error) { throw error } const fallback = propFallback || options.fallback || null if (loading) { return fallback } return render({ fallback, result, options, props: { ...props, ref: forwardedRef }, }) } } const EnhancedInnerLoadable = withChunkExtractor(InnerLoadable) const Loadable = React.forwardRef((props, ref) => ( )) Loadable.displayName = 'Loadable' // In future, preload could use `` Loadable.preload = props => { Loadable.load(props) } Loadable.load = props => { return cachedLoad(props) } return Loadable } function lazy(ctor, options) { return loadable(ctor, { ...options, suspense: true }) } return { loadable, lazy } } export default createLoadable ================================================ FILE: packages/component/src/index.js ================================================ /* eslint-disable no-underscore-dangle */ import * as sharedInternals from './sharedInternals' import * as loadableExports from './loadable' import * as libraryExports from './library' const { loadable } = loadableExports loadable.lib = libraryExports.loadable const { lazy } = loadableExports lazy.lib = libraryExports.lazy export default loadable export { lazy } export { default as loadableReady } from './loadableReady' export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = sharedInternals ================================================ FILE: packages/component/src/library.js ================================================ /* eslint-disable no-use-before-define, react/no-multi-comp */ import createLoadable from './createLoadable' export const { loadable, lazy } = createLoadable({ onLoad(result, props) { if (result && props.forwardedRef) { if (typeof props.forwardedRef === 'function') { props.forwardedRef(result) } else { props.forwardedRef.current = result } } }, render({ result, props }) { if (props.children) { return props.children(result) } return null }, }) ================================================ FILE: packages/component/src/loadable.js ================================================ /* eslint-disable no-use-before-define, react/no-multi-comp */ import React from 'react' import createLoadable from './createLoadable' import { defaultResolveComponent } from './resolvers' export const { loadable, lazy } = createLoadable({ defaultResolveComponent, render({ result: Component, props }) { return }, }) ================================================ FILE: packages/component/src/loadable.test.js ================================================ /* eslint-disable max-classes-per-file */ /* eslint-disable import/no-extraneous-dependencies, react/no-multi-comp */ import 'regenerator-runtime/runtime' import '@testing-library/jest-dom/extend-expect' import React from 'react' import { render, cleanup, wait } from '@testing-library/react' import loadable, { lazy } from './index' afterEach(cleanup) const unresolvableLoad = jest.fn(() => new Promise(() => {})) const resolvedToDefault = value => jest.fn().mockResolvedValue({ default: value }) function mockDelayedResolvedValueOnce(fn, resolvedValue) { return fn.mockImplementationOnce( () => new Promise(resolve => { setTimeout(() => resolve(resolvedValue), 1000) }), ) } class Catch extends React.Component { state = { error: false } static getDerivedStateFromError() { return { error: true } } render() { return this.state.error ? 'error' : this.props.children } } class ErrorBoundary extends React.Component { constructor(props) { super(props) this.state = { error: false, retries: props.retries || 0, } } componentDidCatch() { this.setState(prevState => ({ error: true, retries: prevState.retries - 1, })) } render() { const { children, fallback } = this.props const { error, retries } = this.state if (error) { return (retries >= 0 && children) || fallback || null } return children || null } } describe('#loadable', () => { beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { jest.restoreAllMocks(); }) it('renders nothing without a fallback', () => { const Component = loadable(unresolvableLoad) const { container } = render() expect(container).toBeEmpty() }) it('uses option fallback if specified', () => { const Component = loadable(unresolvableLoad, { fallback: 'progress' }) const { container } = render() expect(container).toHaveTextContent('progress') }) it('uses props fallback if specified', () => { const Component = loadable(unresolvableLoad) const { container } = render() expect(container).toHaveTextContent('progress') }) it('should use props fallback instead of option fallback if specified', () => { const Component = loadable(unresolvableLoad, { fallback: 'opt fallback' }) const { container } = render() expect(container).toHaveTextContent('prop fallback') }) it('mounts component when loaded', async () => { const load = resolvedToDefault(() => 'loaded') const Component = loadable(load) const { container } = render() expect(container).toBeEmpty() await wait(() => expect(container).toHaveTextContent('loaded')) }) it('supports preload', async () => { const load = resolvedToDefault(() => 'loaded') const Component = loadable(load) expect(load).not.toHaveBeenCalled() Component.preload({ foo: 'bar' }) expect(load).toHaveBeenCalledWith({ foo: 'bar' }) expect(load).toHaveBeenCalledTimes(1) const { container } = render() expect(container).toBeEmpty() await wait(() => expect(container).toHaveTextContent('loaded')) expect(load).toHaveBeenCalledTimes(1) }) it('supports commonjs default export', async () => { const load = resolvedToDefault(() => 'loaded') const Component = loadable(load) const { container } = render() await wait(() => expect(container).toHaveTextContent('loaded')) }) it('supports non-default export via resolveComponent', async () => { const importedModule = { exported: () => 'loaded' } const load = jest.fn().mockResolvedValue(importedModule) const resolveComponent = jest.fn(({ exported: component }) => component) const Component = loadable(load, { resolveComponent, }) const { container } = render() await wait(() => expect(container).toHaveTextContent('loaded')) expect(resolveComponent).toHaveBeenCalledWith(importedModule, { someProp: '123', __chunkExtractor: undefined, forwardedRef: null, }) }) it('forwards props', async () => { const load = resolvedToDefault(({ name }) => name) const Component = loadable(load) const { container } = render() await wait(() => expect(container).toHaveTextContent('James Bond')) }) it('should update component if props change', async () => { const load = resolvedToDefault(({ value }) => value) const Component = loadable(load) const { container } = render() await wait(() => expect(container).toHaveTextContent('first')) render(, { container }) await wait(() => expect(container).toHaveTextContent('second')) expect(load).toHaveBeenCalledTimes(1) }) it('calls load func if cacheKey change', async () => { const load = resolvedToDefault(({ value }) => value) const Component = loadable(load, { cacheKey: ({ value }) => value }) const { container } = render() await wait(() => expect(container).toHaveTextContent('first')) expect(load).toHaveBeenCalledTimes(1) render(, { container }) await wait(() => expect(container).toHaveTextContent('second')) expect(load).toHaveBeenCalledTimes(2) }) it('calls load func if resolve change', async () => { const load = resolvedToDefault(({ value }) => value) const Component = loadable({ requireAsync: load, resolve: ({ value }) => value, }) const { container } = render() await wait(() => expect(container).toHaveTextContent('first')) expect(load).toHaveBeenCalledTimes(1) render(, { container }) await wait(() => expect(container).toHaveTextContent('second')) expect(load).toHaveBeenCalledTimes(2) }) it('does not call previous component if cacheKey change', async () => { const A = jest.fn(({ id }) => `A-${id}`) const B = jest.fn(({ id }) => `B-${id}`) const components = { A, B } const load = jest.fn(async ({ name }) => { const Component = components[name] return { default: Component } }) const Component = loadable(load, { cacheKey: ({ name }) => name }) const { container } = render() await wait(() => expect(container).toHaveTextContent('A-0')) expect(load).toHaveBeenCalledTimes(1) expect(load).toHaveBeenCalledWith({ name: 'A', id: 0 }) expect(A).toHaveBeenCalledTimes(1) expect(A).toHaveBeenCalledWith({ name: 'A', id: 0 }, {}) render(, { container }) await wait(() => expect(container).toHaveTextContent('A-1')) expect(A).toHaveBeenCalledTimes(2) expect(A).toHaveBeenCalledWith({ name: 'A', id: 1 }, {}) render(, { container }) await wait(() => expect(container).toHaveTextContent('B-2')) expect(load).toHaveBeenCalledTimes(2) expect(load).toHaveBeenCalledWith({ name: 'B', id: 2 }) expect(B).toHaveBeenCalledTimes(1) expect(B).toHaveBeenCalledWith({ name: 'B', id: 2 }, {}) // A should not have been rendered with "id: 2" expect(A).toHaveBeenCalledTimes(2) }) it('forwards ref', async () => { const load = resolvedToDefault( React.forwardRef((props, fref) =>
), ) const Component = loadable(load) const ref = React.createRef() render() await wait(() => expect(ref.current.tagName).toBe('DIV')) }) it('throws when an error occurs', async () => { const load = jest.fn().mockRejectedValue(new Error('boom')) const Component = loadable(load) const { container } = render( , ) expect(container).toBeEmpty() await wait(() => expect(container).toHaveTextContent('error')) }) it('supports retry from Error Boundary', async () => { const load = jest .fn() .mockRejectedValueOnce(new Error('Error Boundary')) .mockResolvedValueOnce({ default: () => 'loaded' }) const Component = loadable(load) const { container } = render( , ) expect(container).toBeEmpty() await wait(() => expect(container).toHaveTextContent('loaded')) }) }) describe('#lazy', () => { it('supports Suspense', async () => { const load = resolvedToDefault(() => 'loaded') const Component = lazy(load) const { container } = render( , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).not.toHaveTextContent('progress')) expect(container).toHaveTextContent('loaded') }) it('should only render both components when both resolve', async () => { const load = jest .fn() .mockResolvedValueOnce({ default: ({ text }) => text }) mockDelayedResolvedValueOnce(load, { default: ({ text }) => text }) const Component = lazy(load) const { container } = render( <> , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).not.toHaveTextContent('progress')) expect(container.textContent).toBe('AB') }) it("should render multiple elements of the same async component under contextual Suspense'", async () => { const load = resolvedToDefault(({ text }) => text) const Component = lazy(load) const { container } = render( <> , ) expect(container).toHaveTextContent('progressA progressB') await wait(() => expect(container).not.toHaveTextContent('progress')) expect(container).toHaveTextContent('AB') }) it("shouldn't trigger nested Suspense for same lazy component", async () => { const load = resolvedToDefault(({ text }) => text) const Component = lazy(load) const { container } = render( <> , ) expect(container.textContent).toBe('progressA') await wait(() => expect(container).not.toHaveTextContent('progressA')) expect(container).toHaveTextContent('AB') }) it('should support Error Boundary', async () => { const load = jest.fn().mockRejectedValue(new Error('Error Boundary')) const Component = lazy(load) const { container } = render( , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).toHaveTextContent('error')) }) it('should support retry from Error Boundary', async () => { const load = jest .fn() .mockRejectedValueOnce(new Error('Error Boundary')) .mockResolvedValueOnce({ default: () => 'loaded' }) const Component = lazy(load) const { container } = render( , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).toHaveTextContent('loaded')) }) }) describe('#loadable.lib', () => { it('loads library as render prop', async () => { const library = { it: 'is', a: 'lib' } const load = jest.fn().mockResolvedValue(library) const Lib = loadable.lib(load) const renderFn = jest.fn(() => 'loaded') const { container } = render({renderFn}) expect(container).toBeEmpty() await wait(() => expect(container).toHaveTextContent('loaded')) expect(renderFn).toHaveBeenCalledWith(library) }) }) describe('#lazy.lib', () => { it('supports Suspense', async () => { const library = { it: 'is', a: 'lib' } const load = jest.fn().mockResolvedValue(library) const Lib = lazy.lib(load) const renderFn = jest.fn(() => 'loaded') const { container } = render( {renderFn} , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).toHaveTextContent('loaded')) }) it('supports Error Boundary', async () => { const load = jest.fn().mockRejectedValue(new Error('Error Boundary')) const Lib = lazy.lib(load) const renderFn = jest.fn(() => 'loaded') const { container } = render( {renderFn} , ) expect(container).toHaveTextContent('progress') await wait(() => expect(container).toHaveTextContent('error')) }) }) ================================================ FILE: packages/component/src/loadableReady.js ================================================ /* eslint-disable no-underscore-dangle, camelcase */ /* eslint-env browser */ import { warn } from './util' import { getRequiredChunkKey } from './sharedInternals' import { LOADABLE_SHARED } from './shared' const BROWSER = typeof window !== 'undefined' export default function loadableReady( done = () => {}, { namespace = '', chunkLoadingGlobal = '__LOADABLE_LOADED_CHUNKS__' } = {}, ) { if (!BROWSER) { warn('`loadableReady()` must be called in browser only') done() return Promise.resolve() } let requiredChunks = null if (BROWSER) { const id = getRequiredChunkKey(namespace) const dataElement = document.getElementById(id) if (dataElement) { requiredChunks = JSON.parse(dataElement.textContent) const extElement = document.getElementById(`${id}_ext`) if (extElement) { const { namedChunks } = JSON.parse(extElement.textContent) namedChunks.forEach(chunkName => { LOADABLE_SHARED.initialChunks[chunkName] = true }) } else { // version mismatch throw new Error( 'loadable-component: @loadable/server does not match @loadable/component', ) } } } if (!requiredChunks) { warn( '`loadableReady()` requires state, please use `getScriptTags` or `getScriptElements` server-side', ) done() return Promise.resolve() } let resolved = false return new Promise(resolve => { window[chunkLoadingGlobal] = window[chunkLoadingGlobal] || [] const loadedChunks = window[chunkLoadingGlobal] const originalPush = loadedChunks.push.bind(loadedChunks) function checkReadyState() { if ( requiredChunks.every(chunk => loadedChunks.some(([chunks]) => chunks.indexOf(chunk) > -1), ) ) { if (!resolved) { resolved = true resolve() } } } loadedChunks.push = (...args) => { originalPush(...args) checkReadyState() } checkReadyState() }).then(done) } ================================================ FILE: packages/component/src/resolvers.js ================================================ export function defaultResolveComponent(loadedModule) { // eslint-disable-next-line no-underscore-dangle return loadedModule.__esModule ? loadedModule.default : loadedModule.default || loadedModule } ================================================ FILE: packages/component/src/shared.js ================================================ export const LOADABLE_SHARED = { initialChunks: {}, } ================================================ FILE: packages/component/src/sharedInternals.js ================================================ export { invariant } from './util' export { default as Context } from './Context' const LOADABLE_REQUIRED_CHUNKS_KEY = '__LOADABLE_REQUIRED_CHUNKS__' export function getRequiredChunkKey(namespace) { return `${namespace}${LOADABLE_REQUIRED_CHUNKS_KEY}` } ================================================ FILE: packages/component/src/util.js ================================================ /* eslint-disable import/prefer-default-export */ export function invariant(condition, message) { if (condition) return const error = new Error(`loadable: ${message}`) error.framesToPop = 1 error.name = 'Invariant Violation' throw error } export function warn(message) { // eslint-disable-next-line no-console console.warn(`loadable: ${message}`) } ================================================ FILE: packages/server/.npmignore ================================================ src/ .* __fixtures__ ================================================ FILE: packages/server/.size-snapshot.json ================================================ { "dist/cjs/loadable-server.cjs.js": { "bundled": 18673, "minified": 10153, "gzipped": 2842 }, "dist/esm/loadable-server.esm.mjs": { "bundled": 18308, "minified": 9868, "gzipped": 2768, "treeshaked": { "rollup": { "code": 288, "import_statements": 244 }, "webpack": { "code": 13266 } } } } ================================================ FILE: packages/server/CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [5.16.7](https://github.com/gregberge/loadable-components/compare/v5.16.6...v5.16.7) (2025-05-18) **Note:** Version bump only for package @loadable/server ## [5.16.6](https://github.com/gregberge/loadable-components/compare/v5.16.5...v5.16.6) (2025-05-18) **Note:** Version bump only for package @loadable/server ## [5.16.5](https://github.com/gregberge/loadable-components/compare/v5.16.4...v5.16.5) (2024-04-20) **Note:** Version bump only for package @loadable/server ## [5.16.4](https://github.com/gregberge/loadable-components/compare/v5.16.3...v5.16.4) (2024-04-20) ### Bug Fixes * correct esm configuration for loadable/server, fixes: [#999](https://github.com/gregberge/loadable-components/issues/999) ([#1004](https://github.com/gregberge/loadable-components/issues/1004)) ([114cea2](https://github.com/gregberge/loadable-components/commit/114cea2b61ef644d3b794a9b5f48df69f0f5400b)) ## [5.16.2](https://github.com/gregberge/loadable-components/compare/v5.16.1...v5.16.2) (2023-12-15) ### Bug Fixes * add esm exports to package.json and change esm bundle extension to .mjs to allow node.js to properly import esm version of package. ([#989](https://github.com/gregberge/loadable-components/issues/989)) ([e4a3718](https://github.com/gregberge/loadable-components/commit/e4a37188b804e6a5bc66f39c23c738006bc0e284)) ## [5.16.1](https://github.com/gregberge/loadable-components/compare/v5.16.0...v5.16.1) (2023-07-20) ### Bug Fixes * correct babel plugin default signature to allow any source of 'loadable' ([#972](https://github.com/gregberge/loadable-components/issues/972)) ([19849b6](https://github.com/gregberge/loadable-components/commit/19849b6ba738fe19c18e61ed3402ee82ba934760)), closes [#971](https://github.com/gregberge/loadable-components/issues/971) # [5.16.0](https://github.com/gregberge/loadable-components/compare/v5.15.3...v5.16.0) (2023-07-09) **Note:** Version bump only for package @loadable/server ## [5.15.3](https://github.com/gregberge/loadable-components/compare/v5.15.2...v5.15.3) (2023-01-28) ### Bug Fixes * add React 17 and 18 to package dependencies, fixes [#718](https://github.com/gregberge/loadable-components/issues/718) ([66edc37](https://github.com/gregberge/loadable-components/commit/66edc37a731a8ec655deffd3ad454fd96e909ba3)) ## [5.15.2](https://github.com/gregberge/loadable-components/compare/v5.15.1...v5.15.2) (2021-12-12) ### Bug Fixes * Clear correct cache when compiling with Webpack ([#838](https://github.com/gregberge/loadable-components/issues/838)) ([3b9cb20](https://github.com/gregberge/loadable-components/commit/3b9cb202a09365e67c08ec18455d82bedf62f4db)) ## [5.15.1](https://github.com/gregberge/loadable-components/compare/v5.15.0...v5.15.1) (2021-08-17) ### Bug Fixes * SubResourceIntegrity ([#803](https://github.com/gregberge/loadable-components/issues/803)) ([9b34195](https://github.com/gregberge/loadable-components/commit/9b34195627c65372a7c834311c32dfcbd5b7fedd)) # [5.15.0](https://github.com/gregberge/loadable-components/compare/v5.14.2...v5.15.0) (2021-05-08) **Note:** Version bump only for package @loadable/server ## [5.14.2](https://github.com/gregberge/loadable-components/compare/v5.14.1...v5.14.2) (2021-01-31) ### Bug Fixes * ignore css chunk ([#689](https://github.com/gregberge/loadable-components/issues/689)) ([6926e19](https://github.com/gregberge/loadable-components/commit/6926e190c80f525467980fffbbded0bf933f27ed)) * remove main asset path query ([#686](https://github.com/gregberge/loadable-components/issues/686)) ([dde2252](https://github.com/gregberge/loadable-components/commit/dde2252136a2d7f3ff635f85deff429948130883)) # [5.14.0](https://github.com/gregberge/loadable-components/compare/v5.13.2...v5.14.0) (2020-10-20) ### Bug Fixes * add key to chunks script elements ([#631](https://github.com/gregberge/loadable-components/issues/631)) ([25b532e](https://github.com/gregberge/loadable-components/commit/25b532eb53a2841229dbc8a9c91f24112a46b93f)), closes [#628](https://github.com/gregberge/loadable-components/issues/628) * treat mjs as script ([575fe2b](https://github.com/gregberge/loadable-components/commit/575fe2b3f58b18c17416f238780b9bab85110706)) ### Features * make packages webpack 5 compatible ([#638](https://github.com/gregberge/loadable-components/issues/638)) ([e882e4d](https://github.com/gregberge/loadable-components/commit/e882e4d812e714066eba19a11dd119193e7a9e01)) ## [5.13.2](https://github.com/gregberge/loadable-components/compare/v5.13.1...v5.13.2) (2020-09-14) ### Bug Fixes * spread nested required chunks array ([95e6ecb](https://github.com/gregberge/loadable-components/commit/95e6ecb0dd9be3cf18ded934cca433a660fa3543)) ## [5.13.1](https://github.com/gregberge/loadable-components/compare/v5.13.0...v5.13.1) (2020-07-02) ### Bug Fixes * expose used chunkNames from a server. Fixes [#587](https://github.com/gregberge/loadable-components/issues/587) ([831aec0](https://github.com/gregberge/loadable-components/commit/831aec03154ab16007db0d78fbf3559583c000fe)) # [5.13.0](https://github.com/gregberge/loadable-components/compare/v5.12.0...v5.13.0) (2020-06-29) ### Bug Fixes * memory leak in module cache management, fixes [#560](https://github.com/gregberge/loadable-components/issues/560) ([6c11703](https://github.com/gregberge/loadable-components/commit/6c11703cbc5446fc61d10c47b64e84a00cf899c3)) # [5.12.0](https://github.com/gregberge/loadable-components/compare/v5.11.0...v5.12.0) (2020-01-09) ### Bug Fixes * apply loadable transformations before any other, fixes [#466](https://github.com/gregberge/loadable-components/issues/466) ([ac5ba45](https://github.com/gregberge/loadable-components/commit/ac5ba45862bad68b971a969e6e8713874add51a6)) # [5.11.0](https://github.com/smooth-code/loadable-components/compare/v5.10.3...v5.11.0) (2019-12-02) ### Bug Fixes * **server:** use require instead of module.require ([#457](https://github.com/smooth-code/loadable-components/issues/457)) ([064b4f8](https://github.com/smooth-code/loadable-components/commit/064b4f83b291e8a7d73bc44fe4196dc9ddc81fe8)), closes [#455](https://github.com/smooth-code/loadable-components/issues/455) ### Features * add support for SRI (integrity) (with webpack-subresource-integrity) ([#436](https://github.com/smooth-code/loadable-components/issues/436)) ([586ad0a](https://github.com/smooth-code/loadable-components/commit/586ad0af6e172e3a0bffdbe0c8ab682c0d8b0eab)) ## [5.10.3](https://github.com/smooth-code/loadable-components/compare/v5.10.2...v5.10.3) (2019-09-24) ### Bug Fixes * empty cache on each server reload ([#431](https://github.com/smooth-code/loadable-components/issues/431)) ([d4428c6](https://github.com/smooth-code/loadable-components/commit/d4428c6)), closes [#230](https://github.com/smooth-code/loadable-components/issues/230) ## [5.10.2](https://github.com/smooth-code/loadable-components/compare/v5.10.1...v5.10.2) (2019-07-15) ### Performance Improvements * use more performant url join impl ([#353](https://github.com/smooth-code/loadable-components/issues/353)) ([c3fbbef](https://github.com/smooth-code/loadable-components/commit/c3fbbef)) # [5.9.0](https://github.com/smooth-code/loadable-components/compare/v5.8.0...v5.9.0) (2019-04-23) ### Features * support multiple react apps ([#317](https://github.com/smooth-code/loadable-components/issues/317)) ([dc54050](https://github.com/smooth-code/loadable-components/commit/dc54050)), closes [#311](https://github.com/smooth-code/loadable-components/issues/311) * **server:** authorize custom filesystem ([#318](https://github.com/smooth-code/loadable-components/issues/318)) ([f2a6bbd](https://github.com/smooth-code/loadable-components/commit/f2a6bbd)), closes [#315](https://github.com/smooth-code/loadable-components/issues/315) # [5.8.0](https://github.com/smooth-code/loadable-components/compare/v5.7.2...v5.8.0) (2019-04-10) ### Features * **ChunkExtractor:** support publicPath override ([#292](https://github.com/smooth-code/loadable-components/issues/292)) ([9731e9c](https://github.com/smooth-code/loadable-components/commit/9731e9c)) * **server:** support function in attributes ([#277](https://github.com/smooth-code/loadable-components/issues/277)) ([c172324](https://github.com/smooth-code/loadable-components/commit/c172324)) ### Performance Improvements * **server:** improve lodash imports for serverless bundles ([#298](https://github.com/smooth-code/loadable-components/issues/298)) ([96841f2](https://github.com/smooth-code/loadable-components/commit/96841f2)) # [5.7.0](https://github.com/smooth-code/loadable-components/compare/v5.6.1...v5.7.0) (2019-03-14) ### Bug Fixes * **server:** fix loading order of assets ([#266](https://github.com/smooth-code/loadable-components/issues/266)) ([4c8ae60](https://github.com/smooth-code/loadable-components/commit/4c8ae60)) ### Features * use inline JSON to enabling CSP without `unsafe-inline` ([05e5500](https://github.com/smooth-code/loadable-components/commit/05e5500)) ### Performance Improvements * **build:** add build target for Node ([#267](https://github.com/smooth-code/loadable-components/issues/267)) ([97ff6ac](https://github.com/smooth-code/loadable-components/commit/97ff6ac)) ## [5.6.1](https://github.com/smooth-code/loadable-components/compare/v5.6.0...v5.6.1) (2019-02-25) ### Bug Fixes * **server:** allow query-param cache busting in chunk names ([#229](https://github.com/smooth-code/loadable-components/issues/229)) ([71f7bcd](https://github.com/smooth-code/loadable-components/commit/71f7bcd)) * **server:** use `eval` to prevent webpack warning ([#240](https://github.com/smooth-code/loadable-components/issues/240)) ([948165d](https://github.com/smooth-code/loadable-components/commit/948165d)), closes [#234](https://github.com/smooth-code/loadable-components/issues/234) # [5.6.0](https://github.com/smooth-code/loadable-components/compare/v5.5.0...v5.6.0) (2019-02-05) ### Bug Fixes * Add extra props option for links ([#212](https://github.com/smooth-code/loadable-components/issues/212)) ([6714d2a](https://github.com/smooth-code/loadable-components/commit/6714d2a)) # [5.5.0](https://github.com/smooth-code/loadable-components/compare/v5.4.0...v5.5.0) (2019-01-22) ### Features * allow to specify extra attributes in getScriptTags & others ([#210](https://github.com/smooth-code/loadable-components/issues/210)) ([8a3d067](https://github.com/smooth-code/loadable-components/commit/8a3d067)) # [5.4.0](https://github.com/smooth-code/loadable-components/compare/v5.3.0...v5.4.0) (2019-01-17) ### Features * **webpack-plugin:** support custom path in writeToDisk option ([#187](https://github.com/smooth-code/loadable-components/issues/187)) ([4a6f84f](https://github.com/smooth-code/loadable-components/commit/4a6f84f)) # [5.3.0](https://github.com/smooth-code/loadable-components/compare/v5.2.2...v5.3.0) (2019-01-11) ### Features * support inline CSS ([#190](https://github.com/smooth-code/loadable-components/issues/190)) ([2caf676](https://github.com/smooth-code/loadable-components/commit/2caf676)) ## [5.2.2](https://github.com/smooth-code/loadable-components/compare/v5.2.1...v5.2.2) (2018-12-12) ### Bug Fixes * **server:** fix usage when compiled using webpack ([#185](https://github.com/smooth-code/loadable-components/issues/185)) ([5e28870](https://github.com/smooth-code/loadable-components/commit/5e28870)), closes [#181](https://github.com/smooth-code/loadable-components/issues/181) # [5.2.0](https://github.com/smooth-code/loadable-components/compare/v5.1.3...v5.2.0) (2018-11-23) ### Bug Fixes * **server:** fix url join ([#166](https://github.com/smooth-code/loadable-components/issues/166)) ([ba90289](https://github.com/smooth-code/loadable-components/commit/ba90289)) * **server:** support protocol free paths ([#163](https://github.com/smooth-code/loadable-components/issues/163)) ([3b5b115](https://github.com/smooth-code/loadable-components/commit/3b5b115)) ## [5.1.3](https://github.com/smooth-code/loadable-components/compare/v5.1.2...v5.1.3) (2018-11-20) ### Bug Fixes * **server:** exclude http and https from regex ([#155](https://github.com/smooth-code/loadable-components/issues/155)) ([0bb2ad9](https://github.com/smooth-code/loadable-components/commit/0bb2ad9)), closes [#153](https://github.com/smooth-code/loadable-components/issues/153) * **server:** ignore *.hot-update.js ([edcd2c8](https://github.com/smooth-code/loadable-components/commit/edcd2c8)), closes [#148](https://github.com/smooth-code/loadable-components/issues/148) ## [5.1.1](https://github.com/smooth-code/loadable-components/compare/v5.1.0...v5.1.1) (2018-11-13) ### Bug Fixes * **server:** ignore source maps ([9991bbd](https://github.com/smooth-code/loadable-components/commit/9991bbd)), closes [#128](https://github.com/smooth-code/loadable-components/issues/128) # [5.1.0](https://github.com/smooth-code/loadable-components/compare/v5.0.2...v5.1.0) (2018-11-10) ### Features * **server:** add outputPath option in ChunkExtractor ([aac26b3](https://github.com/smooth-code/loadable-components/commit/aac26b3)) ## [5.0.2](https://github.com/smooth-code/loadable-components/compare/v5.0.1...v5.0.2) (2018-11-10) ### Bug Fixes * update peer dependencies ([b0363dc](https://github.com/smooth-code/loadable-components/commit/b0363dc)) # [5.0.0](https://github.com/smooth-code/loadable-components/compare/v4.0.5...v5.0.0) (2018-11-10) ### Features * improve SSR support ([eb1cfe8](https://github.com/smooth-code/loadable-components/commit/eb1cfe8)) ### BREAKING CHANGES * - SSR has been rewritten from scratch, if you use it, please follow the new guide. - Prefetch component and prefetch functions have been removed, please use `webpackPrefetch` instead. ## [4.0.5](https://github.com/smooth-code/loadable-components/compare/v4.0.4...v4.0.5) (2018-11-01) ### Bug Fixes * **server:** fix getScriptElements ([ba424e0](https://github.com/smooth-code/loadable-components/commit/ba424e0)) ## [4.0.4](https://github.com/smooth-code/loadable-components/compare/v4.0.3...v4.0.4) (2018-10-31) ### Bug Fixes * fix peer dependencies ([6816e8c](https://github.com/smooth-code/loadable-components/commit/6816e8c)) ## [4.0.3](https://github.com/smooth-code/loadable-components/compare/v4.0.2...v4.0.3) (2018-10-31) ### Bug Fixes * **server:** disable common chunks optim ([78e7b28](https://github.com/smooth-code/loadable-components/commit/78e7b28)) # [4.0.0](https://github.com/smooth-code/loadable-components/compare/v3.0.2...v4.0.0) (2018-10-30) **Note:** Version bump only for package @loadable/server # [3.0.0](https://github.com/smooth-code/loadable-components/compare/v2.2.3...v3.0.0) (2018-10-29) ### Features * welcome loadable ([4dffad7](https://github.com/smooth-code/loadable-components/commit/4dffad7)) ### BREAKING CHANGES * API has completely changed, see documentation. ================================================ FILE: packages/server/README.md ================================================ # @loadable/server ## Install ``` npm install @loadable/server ``` ## Documentation 👉 [See full documentation](https://loadable-components.com/) ## License MIT ================================================ FILE: packages/server/__fixtures__/stats.json ================================================ { "errors": [], "warnings": [], "hash": "6cacb38ddc45b9bbd140", "publicPath": "/dist/node/", "outputPath": "../../examples/server-side-rendering/public/dist/node", "assetsByChunkName": { "Y-file": "Y-file.js", "letters-A": [ "letters-A.css", "letters-A.js" ], "letters-A-css": [ "letters-A-css.css", "letters-A-css.js" ], "letters-B": "letters-B.js", "letters-C": "letters-C.js", "letters-D": "letters-D.js", "letters-E": "letters-E.js", "letters-E-param": "letters-E-param.js", "letters-F": "letters-F.js", "letters-G": "letters-G.js", "letters-Z-file": "letters-Z-file.js", "main": [ "main.css", "main.js" ] }, "assets": [ { "name": "Y-file.js", "size": 121, "chunks": [ "Y-file" ], "chunkNames": [ "Y-file" ], "info": {}, "emitted": false }, { "name": "letters-A-css.css", "size": 43, "chunks": [ "letters-A-css" ], "chunkNames": [ "letters-A-css" ], "info": {}, "emitted": false }, { "name": "letters-A-css.js", "size": 95, "chunks": [ "letters-A-css" ], "chunkNames": [ "letters-A-css" ], "info": {}, "emitted": false }, { "name": "letters-A.css", "size": 43, "chunks": [ "letters-A", "letters-A-css" ], "chunkNames": [ "letters-A" ], "info": {}, "emitted": false }, { "name": "letters-A.js", "size": 272, "chunks": [ "letters-A", "letters-A-css" ], "chunkNames": [ "letters-A" ], "info": {}, "emitted": false }, { "name": "letters-B.js", "size": 173, "chunks": [ "letters-B" ], "chunkNames": [ "letters-B" ], "info": {}, "emitted": false }, { "name": "letters-C.js", "size": 127, "chunks": [ "letters-C" ], "chunkNames": [ "letters-C" ], "info": {}, "emitted": false }, { "name": "letters-D.js", "size": 127, "chunks": [ "letters-D" ], "chunkNames": [ "letters-D" ], "info": {}, "emitted": false }, { "name": "letters-E-param.js", "size": 139, "chunks": [ "letters-E-param" ], "chunkNames": [ "letters-E-param" ], "info": {}, "emitted": false }, { "name": "letters-E.js", "size": 127, "chunks": [ "letters-E" ], "chunkNames": [ "letters-E" ], "info": {}, "emitted": false }, { "name": "letters-F.js", "size": 127, "chunks": [ "letters-F" ], "chunkNames": [ "letters-F" ], "info": {}, "emitted": false }, { "name": "letters-G.js", "size": 222, "chunks": [ "letters-G" ], "chunkNames": [ "letters-G" ], "info": {}, "emitted": false }, { "name": "letters-Z-file.js", "size": 137, "chunks": [ "letters-Z-file" ], "chunkNames": [ "letters-Z-file" ], "info": {}, "emitted": false }, { "name": "main.css", "size": 39, "chunks": [ "main" ], "chunkNames": [ "main" ], "info": {}, "emitted": false }, { "name": "main.js", "size": 13582, "chunks": [ "main" ], "chunkNames": [ "main" ], "info": {}, "emitted": false } ], "filteredAssets": 0, "namedChunkGroups": { "main": { "chunks": [ "main" ], "assets": [ "main.css", "main.js" ], "children": { "preload": [ { "name": "letters-C", "chunks": [ "letters-C" ], "assets": [ "letters-C.js" ] } ], "prefetch": [ { "name": "letters-D", "chunks": [ "letters-D" ], "assets": [ "letters-D.js" ] } ] }, "childAssets": { "preload": [ "letters-C.js" ], "prefetch": [ "letters-D.js" ] } }, "letters-A": { "chunks": [ "letters-A" ], "assets": [ "letters-A.css", "letters-A.js" ], "children": {}, "childAssets": {} }, "letters-B": { "chunks": [ "letters-B" ], "assets": [ "letters-B.js" ], "children": {}, "childAssets": {} }, "letters-C": { "chunks": [ "letters-C" ], "assets": [ "letters-C.js" ], "children": {}, "childAssets": {} }, "letters-D": { "chunks": [ "letters-D" ], "assets": [ "letters-D.js" ], "children": {}, "childAssets": {} }, "letters-E-param": { "chunks": [ "letters-E-param" ], "assets": [ "letters-E-param.js" ], "children": {}, "childAssets": {} }, "letters-G": { "chunks": [ "letters-G" ], "assets": [ "letters-G.js" ], "children": {}, "childAssets": {} }, "moment": { "chunks": [], "assets": [], "children": {}, "childAssets": {} }, "letters-A-css": { "chunks": [ "letters-A-css" ], "assets": [ "letters-A-css.css", "letters-A-css.js" ], "children": {}, "childAssets": {} }, "letters-A-js": { "chunks": [ "letters-A" ], "assets": [ "letters-A.css", "letters-A.js" ], "children": {}, "childAssets": {} }, "letters-B-js": { "chunks": [ "letters-B" ], "assets": [ "letters-B.js" ], "children": {}, "childAssets": {} }, "letters-C-js": { "chunks": [ "letters-C" ], "assets": [ "letters-C.js" ], "children": {}, "childAssets": {} }, "letters-D-js": { "chunks": [ "letters-D" ], "assets": [ "letters-D.js" ], "children": {}, "childAssets": {} }, "letters-E": { "chunks": [ "letters-E" ], "assets": [ "letters-E.js" ], "children": {}, "childAssets": {} }, "letters-E-js": { "chunks": [ "letters-E" ], "assets": [ "letters-E.js" ], "children": {}, "childAssets": {} }, "letters-F": { "chunks": [ "letters-F" ], "assets": [ "letters-F.js" ], "children": {}, "childAssets": {} }, "letters-F-js": { "chunks": [ "letters-F" ], "assets": [ "letters-F.js" ], "children": {}, "childAssets": {} }, "letters-G-js": { "chunks": [ "letters-G" ], "assets": [ "letters-G.js" ], "children": {}, "childAssets": {} }, "letters-Z-file": { "chunks": [ "letters-Z-file" ], "assets": [ "letters-Z-file.js" ], "children": {}, "childAssets": {} }, "letters-Z-file-js": { "chunks": [ "letters-Z-file" ], "assets": [ "letters-Z-file.js" ], "children": {}, "childAssets": {} }, "Y-file": { "chunks": [ "Y-file" ], "assets": [ "Y-file.js" ], "children": {}, "childAssets": {} } }, "generator": "loadable-components", "chunks": [ { "id": "Y-file", "files": [ "Y-file.js" ] }, { "id": "letters-A", "files": [ "letters-A.css", "letters-A.js" ] }, { "id": "letters-A-css", "files": [ "letters-A-css.css", "letters-A-css.js" ] }, { "id": "letters-B", "files": [ "letters-B.js" ] }, { "id": "letters-C", "files": [ "letters-C.js" ] }, { "id": "letters-D", "files": [ "letters-D.js" ] }, { "id": "letters-E", "files": [ "letters-E.js" ] }, { "id": "letters-E-param", "files": [ "letters-E-param.js" ] }, { "id": "letters-F", "files": [ "letters-F.js" ] }, { "id": "letters-G", "files": [ "letters-G.js" ] }, { "id": "letters-Z-file", "files": [ "letters-Z-file.js" ] }, { "id": "main", "files": [ "main.css", "main.js" ] } ] } ================================================ FILE: packages/server/package.json ================================================ { "name": "@loadable/server", "description": "Server utilities for loadable.", "version": "5.16.7", "type": "module", "main": "./dist/cjs/loadable-server.cjs.js", "module": "./dist/esm/loadable-server.esm.mjs", "exports": { ".": { "require": "./dist/cjs/loadable-server.cjs.js", "import": "./dist/esm/loadable-server.esm.mjs", "default": "./dist/cjs/loadable-server.cjs.js" } }, "repository": "git@github.com:gregberge/loadable-components.git", "author": "Greg Bergé ", "publishConfig": { "access": "public" }, "keywords": [ "loadable" ], "engines": { "node": ">=8" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" }, "license": "MIT", "scripts": { "prebuild": "shx rm -rf dist", "build": "cross-env rollup -c && yarn create-cjs-package-json", "create-cjs-package-json": "echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", "prepublishOnly": "yarn run build", "update-fixtures": "yarn --cwd ../../examples/__fixtures__ build:webpack && rm -rf ./__fixtures__ && cp -R ../../examples/__fixtures__/target ./__fixtures__ " }, "peerDependencies": { "@loadable/component": "^5.0.1", "react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "devDependencies": { "@loadable/component": "^5.16.7" }, "dependencies": { "lodash": "^4.17.15" } } ================================================ FILE: packages/server/rollup.config.js ================================================ /* eslint-disable import/no-extraneous-dependencies */ import nodeResolve from 'rollup-plugin-node-resolve' import babel from 'rollup-plugin-babel' import replace from 'rollup-plugin-replace' import commonjs from 'rollup-plugin-commonjs' import { terser } from 'rollup-plugin-terser' import pkg from './package.json' const input = 'src/index.js' const name = 'loadable' const globals = { react: 'React', 'hoist-non-react-statics': 'hoistNonReactStatics', } const external = id => !id.startsWith('.') && !id.startsWith('/') const getBabelOptions = ({ useESModules }) => ({ exclude: '**/node_modules/**', runtimeHelpers: true, presets: [ ['@babel/preset-env', { loose: true }], ['@babel/preset-react', { useBuiltIns: true }], ], plugins: [ '@babel/plugin-proposal-class-properties', 'babel-plugin-annotate-pure-calls', ['@babel/plugin-transform-runtime', { useESModules }], ], }) export default [ // cjs { input, output: { file: pkg.main, format: 'cjs', exports: 'named' }, external, plugins: [babel(getBabelOptions({ useESModules: false }))], }, // esm { input, output: { file: pkg.module, format: 'esm' }, external, plugins: [babel(getBabelOptions({ useESModules: true }))], }, ] ================================================ FILE: packages/server/src/ChunkExtractor.js ================================================ /* eslint-disable react/no-danger */ import path from 'path' import fs from 'fs' import uniq from 'lodash/uniq.js' import uniqBy from 'lodash/uniqBy.js' import flatMap from 'lodash/flatMap.js' import React from 'react' import { invariant, getRequiredChunkKey } from './sharedInternals.js' import ChunkExtractorManager from './ChunkExtractorManager.js' import { smartRequire, joinURLPath, readJsonFileSync } from './util.js' const EXTENSION_SCRIPT_TYPES = { '.js': 'script', '.mjs': 'script', '.css': 'style', } function extensionToScriptType(extension) { return EXTENSION_SCRIPT_TYPES[extension] || null } /** * some files can be references with extra query arguments which have to be removed * @param name * @returns {*} */ function cleanFileName(name) { return name.split('?')[0] } function getFileScriptType(fileName) { return extensionToScriptType( cleanFileName(path.extname(fileName)).toLowerCase(), ) } function isScriptFile(fileName) { return getFileScriptType(fileName) === 'script' } function getAssets(chunks, getAsset) { return uniqBy( flatMap(chunks, chunk => getAsset(chunk)), 'url', ) } function handleExtraProps(asset, extraProps) { return typeof extraProps === 'function' ? extraProps(asset) : extraProps } function extraPropsToString(asset, extraProps) { return Object.entries(handleExtraProps(asset, extraProps)).reduce( (acc, [key, value]) => `${acc} ${key}="${value}"`, '', ) } function getSriHtmlAttributes(asset) { if (!asset.integrity) { return '' } return ` integrity="${asset.integrity}"` } function assetToScriptTag(asset, extraProps) { return `` } function assetToScriptElement(asset, extraProps) { return ( `, ``, ].join('') } getRequiredChunksScriptElements(extraProps) { const id = getRequiredChunkKey(this.namespace) const props = { type: 'application/json', ...handleExtraProps(null, extraProps), } return [ " `) }) it('should return main script tag without chunk with namespaced required chunks id', () => { const testExtractor = new ChunkExtractor({ namespace: 'testapp', stats, outputPath: path.resolve(__dirname, '../__fixtures__'), }) expect(testExtractor.getScriptTags()).toMatchInlineSnapshot(` " " `) }) it('should return other chunks if referenced', () => { extractor.addChunk('letters-A') expect(extractor.getScriptTags()).toMatchInlineSnapshot(` " " `) }) // no longer matching anything it.skip('should allow for query params in chunk names', () => { extractor.addChunk('letters-E') expect(extractor.getScriptTags()).toMatchInlineSnapshot(` " " `) }) it('should add integrity if available in stats', () => { const testExtractor = new ChunkExtractor({ stats: { ...stats, namedChunkGroups: { ...stats.namedChunkGroups, main: { ...stats.namedChunkGroups.main, assets: stats.namedChunkGroups.main.assets.map(name => ({ name, // pseudo hash - reversed name integrity: name .split('') .reverse() .join(''), })), }, }, }, outputPath: targetPath, }) expect(testExtractor.getScriptTags({ crossorigin: 'anonymous' })) .toMatchInlineSnapshot(` " " `) }) it('should add extra props if specified - object argument', () => { extractor.addChunk('letters-A') expect(extractor.getScriptTags({ nonce: 'testnonce' })) .toMatchInlineSnapshot(` " " `) }) it('should add extra props if specified - function argument', () => { extractor.addChunk('letters-A') expect( extractor.getScriptTags(asset => { return { nonce: asset ? asset.chunk : 'anonymous' } }), ).toMatchInlineSnapshot(` " " `) }) }) describe('#getScriptElements', () => { it('should return main script tag without chunk with namespaced id for loadable chunks', () => { const testExtractor = new ChunkExtractor({ namespace: 'testapp', stats, outputPath: path.resolve(__dirname, '../__fixtures__'), }) expect(testExtractor.getScriptElements()).toMatchInlineSnapshot(` Array [