diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 4d35c8236d3..00000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,88 +0,0 @@ -version: 2 - -jobs: - analysis: - docker: - - image: rollupcabal/circleci-node-base:latest - steps: - - checkout - - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: Installing Dependencies - command: npm ci --ignore-scripts - - run: - name: Running linting - command: npm run ci:lint - - run: - name: Running NPM Security Audit - command: npm run security - - save_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - paths: - - ./node_modules - node-v10-latest: - docker: - - image: rollupcabal/circleci-node-v10:latest - steps: - - checkout - - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: Running tests - command: npm run ci:test - node-v12-latest: - docker: - - image: rollupcabal/circleci-node-v12:latest - steps: - - checkout - - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: Running tests - command: npm run ci:test:only - - store_artifacts: - name: Storing browser build for REPL - path: /home/circleci/project/dist/rollup.browser.js - destination: rollup.browser.js - - run: - name: Post REPL comment - command: ./scripts/post-comment.js - node-v14-latest: - docker: - - image: rollupcabal/circleci-node-v14:latest - steps: - - checkout - - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: Running tests with coverage - command: npm run ci:coverage - - -workflows: - version: 2 - validate-test: - jobs: - - analysis: - filters: - tags: - only: /.*/ - - node-v10-latest: - requires: - - analysis - filters: - tags: - only: /.*/ - - node-v12-latest: - requires: - - analysis - filters: - tags: - only: /.*/ - - node-v14-latest: - requires: - - analysis - filters: - tags: - only: /.*/ diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..8b9efb3da4c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,91 @@ +module.exports = { + env: { + browser: true, + es6: true, + node: true + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + 'plugin:prettier/recommended', + 'plugin:import/recommended', + 'plugin:import/typescript' + ], + ignorePatterns: [ + 'node_modules/**/*.*', + 'dist/**/*.*', + '/test/**/*.*', + '!/test/*.js', + '!/test/*/*.js', + '/test/node_modules/*.*', + '!/test/*/samples/**/_config.js' + ], + overrides: [ + { + files: ['*.js'], + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off' + } + }, + { + files: ['*.js', 'cli/**/*.ts'], + rules: { + '@typescript-eslint/no-var-requires': 'off' + } + }, + { + env: { + mocha: true + }, + files: ['test/**/*.js'], + rules: { + 'sort-keys': 'off' + } + } + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module' + }, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/consistent-type-assertions': [ + 'error', + { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' } + ], + '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], + '@typescript-eslint/member-ordering': [ + 'error', + { + default: { + memberTypes: require('@typescript-eslint/eslint-plugin/dist/rules/member-ordering') + .defaultOrder, + order: 'alphabetically' + } + } + ], + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unused-vars': 'off', + 'dot-notation': 'error', + 'import/no-unresolved': ['error', { ignore: ['package.json', 'is-reference', 'help.md'] }], + 'import/order': ['error', { alphabetize: { order: 'asc' } }], + 'no-constant-condition': ['error', { checkLoops: false }], + 'no-prototype-builtins': 'off', + 'object-shorthand': 'error', + 'prefer-const': ['error', { destructuring: 'all' }], + 'prefer-object-spread': 'error', + 'sort-imports': [ + 'error', + { + ignoreCase: true, + ignoreDeclarationSort: true, + ignoreMemberSort: false + } + ], + 'sort-keys': ['error', 'asc', { caseSensitive: false }] + } +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 63fa0daa3aa..00000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "ignorePatterns": [ - "test/*/samples/**/*.js", - "!test/*/samples/**/_config.js", - "test/leak/index.js", - "**/*.ts" - ], - "rules": { - "indent": [ 2, "tab", { "SwitchCase": 1 } ], - "semi": [ 2, "always" ], - "keyword-spacing": [ 2, { "before": true, "after": true } ], - "space-before-blocks": [ 2, "always" ], - "no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ], - "no-cond-assign": 0, - "no-unused-vars": 2, - "object-shorthand": [ 2, "always" ], - "no-const-assign": 2, - "no-class-assign": 2, - "no-this-before-super": 2, - "no-var": 2, - "no-unreachable": 2, - "valid-typeof": 2, - "quote-props": [ 2, "as-needed" ], - "one-var": [ 2, "never" ], - "prefer-arrow-callback": 2, - "prefer-const": [ 2, { "destructuring": "all" } ], - "arrow-spacing": 2 - }, - "env": { - "es6": true, - "browser": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:import/errors", - "plugin:import/warnings" - ], - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "settings": { - "import/ignore": [ 0, [ - "\\.path.js$" - ] ] - } -} diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b3ed2280246..01c83e8a1d6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,6 +1,6 @@ ### Description diff --git a/.github/workflows/node-windows.yml b/.github/workflows/node-windows.yml deleted file mode 100644 index 406080460d0..00000000000 --- a/.github/workflows/node-windows.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Node - -on: [push] - -jobs: - build: - runs-on: windows-2019 - - strategy: - matrix: - node: ['14', '12', '10'] - - name: ${{ matrix.node }} (Windows) - steps: - - name: Configure git line-breaks - run: git config --global core.autocrlf false - - name: Checkout Commit - uses: actions/checkout@v1 - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node }} - - name: Install dependencies - run: npm ci --ignore-scripts - - name: Run tests - run: npm test - env: - CI: true diff --git a/.github/workflows/repl-artefacts.yml b/.github/workflows/repl-artefacts.yml new file mode 100644 index 00000000000..46be3135023 --- /dev/null +++ b/.github/workflows/repl-artefacts.yml @@ -0,0 +1,68 @@ +name: Upload REPL artefacts + +on: + pull_request_target: + +jobs: + upload: + runs-on: ubuntu-latest + name: Upload + steps: + - name: Checkout Commit + uses: actions/checkout@v2 + with: + ref: refs/pull/${{ github.event.number }}/merge + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: 14 + - name: Install dependencies + run: npm ci --ignore-scripts + - name: Build artefacts + run: npm run build:cjs && npm run build:bootstrap + - name: Upload "${{ github.event.number }}/rollup.browser.js" to bucket + uses: zdurham/s3-upload-github-action@master + with: + args: --cache-control max-age=300,public + env: + FILE: dist/rollup.browser.js + AWS_REGION: ${{ secrets.AWS_REGION }} + S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_KEY: ${{ github.event.number }}/rollup.browser.js + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Upload "${{ github.event.number }}/rollup.browser.js.map" to bucket + uses: zdurham/s3-upload-github-action@master + with: + args: --cache-control max-age=300,public + env: + FILE: dist/rollup.browser.js.map + AWS_REGION: ${{ secrets.AWS_REGION }} + S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_KEY: ${{ github.event.number }}/rollup.browser.js.map + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Find Comment + uses: peter-evans/find-comment@v1 + id: fc + with: + issue-number: ${{ github.event.number }} + comment-author: 'github-actions[bot]' + body-includes: 'Thank you for your contribution!' + - name: Create or update comment + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.number }} + edit-mode: replace + body: | + ### Thank you for your contribution! ❤️ + + You can try out this pull request locally by installing Rollup via + + ```bash + npm install ${{ github.event.pull_request.head.repo.full_name }}#${{ github.event.pull_request.head.ref }} + ``` + + or load it into the REPL: + https://rollupjs.org/repl/?pr=${{ github.event.number }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000000..a30c3a65cdb --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,90 @@ +name: Tests + +on: + push: + branches: + - master + pull_request: + +jobs: + linux14: + runs-on: ubuntu-latest + name: Node 14 + Coverage (Linux) + steps: + - name: Checkout Commit + uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Install dependencies + run: npm ci --ignore-scripts + - name: Run tests with coverage + run: npm run ci:coverage + env: + CI: true + - uses: codecov/codecov-action@v1 + with: + commit_parent: ${{ github.event.pull_request.head.sha }} + + linux12: + runs-on: ubuntu-latest + name: Node 12 + Extra Tests (Linux) + steps: + - name: Checkout Commit + uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '12' + - name: Install dependencies + run: npm ci --ignore-scripts + - name: Lint + run: npm run ci:lint + - name: Vulnerabilities + run: npm run security + - name: Run all tests + run: npm run ci:test + env: + CI: true + + linux10: + runs-on: ubuntu-latest + name: Node 10 (Linux) + steps: + - name: Checkout Commit + uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '10' + - name: Install dependencies + run: npm ci --ignore-scripts + - name: Run tests + run: npm run ci:test:only + env: + CI: true + + windows: + runs-on: windows-2019 + strategy: + matrix: + node: ['10', '12', '14', '16'] + name: Node ${{ matrix.node }} (Windows) + steps: + - name: Configure git line-breaks + run: git config --global core.autocrlf false + - name: Checkout Commit + uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - name: Install dependencies + run: npm ci --ignore-scripts + - name: Run tests + run: npm test + env: + CI: true diff --git a/.gitignore b/.gitignore index 988fb26eb0a..dd514aee05d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ _actual.js coverage .commithash .idea +.eslintcache test/_tmp test/hooks/tmp test/tmp diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 00000000000..31354ec1389 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000000..36af219892f --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.huskyrc b/.huskyrc deleted file mode 100644 index 93be133c0df..00000000000 --- a/.huskyrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "hooks": { - "pre-commit": "lint-staged", - "post-commit": "git reset" - } -} diff --git a/.lintstagedrc b/.lintstagedrc deleted file mode 100644 index c2078e45c9a..00000000000 --- a/.lintstagedrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "{src,bin,browser,typings}/**/*.ts": [ - "prettier --write", - "tslint --project . --fix" - ], - "test/typescript/**/*.ts": [ - "prettier --write", - "tslint --project test/typescript --fix" - ], - "{test/test,test/*/index,test/utils,test/**/_config}.js": [ - "prettier --write", - "eslint --fix" - ] -} diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 00000000000..c9c66585f1a --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,5 @@ +module.exports = { + '.ts': ['eslint --fix --cache'], + '!(test/**/*).js': ['eslint --fix --cache'], + '{test/*,test/*/*,test/*/samples/**/_config}.js': ['eslint --fix --cache'] +}; diff --git a/.mocharc.json b/.mocharc.json deleted file mode 100644 index 320d59dfe0e..00000000000 --- a/.mocharc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "spec": "test/test.js" -} diff --git a/.nycrc b/.nycrc index 73750dd99c3..af7db356dc9 100644 --- a/.nycrc +++ b/.nycrc @@ -1,4 +1,4 @@ { - "exclude": ["*commonjsHelpers.js", "test"], + "exclude": ["test"], "extension": [".ts", ""] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 6f554c9d2dd..0b731fb0af3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,7 +1,4 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { @@ -11,7 +8,7 @@ "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", "args": [ "-u", - "tdd", + "bdd", "--timeout", "999999", "--colors" diff --git a/.vscode/settings.json b/.vscode/settings.json index 0208e5b23c5..d84818e43f3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ -// Place your settings in this file to overwrite default and user settings. { "typescript.format.insertSpaceBeforeFunctionParenthesis": true, "typescript.format.insertSpaceAfterConstructor": true, - "typescript.format.enable": true + "typescript.format.enable": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } } diff --git a/CHANGELOG.md b/CHANGELOG.md index fb5e42ee518..80f036c8a4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,600 @@ # rollup changelog +## 2.51.2 +*2021-06-11* + +### Bug Fixes +* Include modules imported from no-treeshake modules even if they would be empty (#4138) + +### Pull Requests +* [#4138](https://github.com/rollup/rollup/pull/4138): Include all dependencies from modules with no-treeshake (@lukastaegert) + +## 2.51.1 +*2021-06-08* + +### Bug Fixes +* Fix error when using `defineConfig` (#4134) + +### Pull Requests +* [#4134](https://github.com/rollup/rollup/pull/4134): export `rollup.defineConfig` at runtime (@mshrtsr) + +## 2.51.0 +*2021-06-06* + +### Features +* Add a helper for IntelliSense support in config files (#4127) + +### Bug Fixes +* Improve performance when generating source maps (#4122) + +### Pull Requests +* [#4122](https://github.com/rollup/rollup/pull/4122): User Map to optimize performance (@izevo) +* [#4127](https://github.com/rollup/rollup/pull/4127): Export defineConfig defines the auxiliary function of the configuration (@rxliuli) + +## 2.50.6 +*2021-06-03* + +### Bug Fixes +* Do not consider the object spread operator as side effect when `propertyReadSideEffects` are false (#4119) +* Detect side effects when returning thenables from async arrow functions (#4120) + +### Pull Requests +* [#4119](https://github.com/rollup/rollup/pull/4119): Respect propertyReadSideEffects in spread elements (@lukastaegert) +* [#4120](https://github.com/rollup/rollup/pull/4120): Detect async arrow thenable side effects (@lukastaegert) + +## 2.50.5 +*2021-05-30* + +### Bug Fixes +* Detect side effects when accessing thenables (#4115) + +### Pull Requests +* [#4114](https://github.com/rollup/rollup/pull/4114): use `colorette` instead of `turbocolor` (@ryuever) +* [#4115](https://github.com/rollup/rollup/pull/4115): Tracks side effects of thenables (@lukastaegert) + +## 2.50.4 +*2021-05-29* + +### Bug Fixes +* Fix a situation where tree-shaking would stop including nodes prematurely (#4111) +* Track mutations and accessor side effects when using `__proto__` in an object literal (#4112) +* Check for getter effects when spreading an object (#4113) + +### Pull Requests +* [#4111](https://github.com/rollup/rollup/pull/4111): Always request a new tree-shaking pass when deoptimizations of a node are first included (@lukastaegert) +* [#4112](https://github.com/rollup/rollup/pull/4112): Actually set the prototype when using a __proto__ property (@lukastaegert) +* [#4113](https://github.com/rollup/rollup/pull/4113): Track access side effects when using object spread operator (@lukastaegert) + +## 2.50.3 +*2021-05-28* + +### Bug Fixes +* Wrap parentheses around leading elements in simplified sequence expressions if this would otherwise lead to invalid code (#4110) +* Do not associate block soped variables in catch clauses with the clause parameter (#4108) +* Do not associate hoisted variables in catch clauses with outside variables if they match the parameter (#4108) +* Use correct "this" context for tagged template literal member expressions in simplified sequences (#4110) + +### Pull Requests +* [#4108](https://github.com/rollup/rollup/pull/4108): Correctly handle catch declarations (@lukastaegert) +* [#4110](https://github.com/rollup/rollup/pull/4110): Invalid sequence expression simplification (@lukastaegert) + +## 2.50.2 +*2021-05-27* + +### Bug Fixes +* Avoid unnecessary side effects when using methods like `.filter` and `.map` (#4103) +* Avoid crash when a module with moduleSideEffects no-treeshake imports a tree-shaken module (#4104) + +### Pull Requests +* [#4103](https://github.com/rollup/rollup/pull/4103): Do not track side-effect-free array methods as side effects (@lukastaegert) +* [#4104](https://github.com/rollup/rollup/pull/4104): Fix crash when using inlineDynamicImports with no-treeshake (@lukastaegert) + +## 2.50.1 +*2021-05-26* + +### Bug Fixes +* Do not associate pure annotations in simplified expressions with wrong elements (#4095) +* Prevent invalid code when simplified conditionals start with an IIFE function expression (#4099) + +### Pull Requests +* [#4095](https://github.com/rollup/rollup/pull/4095): Correctly associate pure annotations and remove invalid ones (@lukastaegert) +* [#4099](https://github.com/rollup/rollup/pull/4099): Wrap leading function expression iifes in conditionals (@lukastaegert) + +## 2.50.0 +*2021-05-25* + +### Features +* Only include last elements of comma expressions if they are used or have side effects (#4087) + +### Bug Fixes +* Prevent a crash that could occur when calling object methods (#4091) + +### Pull Requests +* [#4085](https://github.com/rollup/rollup/pull/4085): Switch to ESLint (@lukastaegert) +* [#4087](https://github.com/rollup/rollup/pull/4087): Drop unused last sequence element (@lukastaegert) +* [#4091](https://github.com/rollup/rollup/pull/4091): Prevent crash for recursive "this" deoptimization (@lukastaegert) + +## 2.49.0 +*2021-05-23* + +### Features +* Detect side-effect-free static class methods and properties (#4018) +* Detect side-effect-free array elements (#4018) +* Do not apply deoptimizations from dead code (#4018) + +### Bug Fixes +* Handle side effect detection for getters and setters added in untracked code (#4018) +* Track "this" mutations for methods, getters and setters (#4018) + +### Pull Requests +* [#4018](https://github.com/rollup/rollup/pull/4018): Class method effects (@marijnh and @lukastaegert) + +## 2.48.0 +*2021-05-15* + +### Features +* Add replacement to conditionally insert asset extensions in `entryFileNames` when preserving modules (#4077) + +### Bug Fixes +* Fix crash when dynamically assigning to namespace members (#4070) +* Do not associate pure annotations in front of a semi-colon or comma with succeeding code (#4068) + +### Pull Requests +* [#4068](https://github.com/rollup/rollup/pull/4068): ignore invalid trailing pure annotations (@kzc) +* [#4070](https://github.com/rollup/rollup/pull/4070): undefined `deoptimizePath` when the first element is empty string (@si3nloong) +* [#4071](https://github.com/rollup/rollup/pull/4071): add node.js v16 support (@dnalborczyk) +* [#4077](https://github.com/rollup/rollup/pull/4077): Add assetExtname replacement in entryFileNames (@BPScott) +* [#4080](https://github.com/rollup/rollup/pull/4080): Added Rollup logo in README.md (@priyanshurav) +* [#4081](https://github.com/rollup/rollup/pull/4081): fix comment regarding invalid annotation handling (@kzc) + +## 2.47.0 +*2021-05-04* + +### Features +* Warn about ambiguous imports from combined external namespace reexports (#4064) +* In case of combined namespace reexports, always prefer local exports over external namespaces (#4064) +* Treat conflicting names in local namespace reexports as undefined (#4064) + +### Pull Requests +* [#4064](https://github.com/rollup/rollup/pull/4064): Prefer locally defined exports and reexports over external namespaces (@lukastaegert) + +## 2.46.0 +*2021-04-29* + +### Features +* Add option to disable file name sanitation (#4058) +* Add information about importers to unused external import warning (#4054) + +### Pull Requests +* [#4042](https://github.com/rollup/rollup/pull/4042): Use Github actions only (@lukastaegert) +* [#4045](https://github.com/rollup/rollup/pull/4045): Fix REPL artefact branch reference (@lukastaegert) +* [#4046](https://github.com/rollup/rollup/pull/4046): Use codecov action for coverage (@lukastaegert) +* [#4054](https://github.com/rollup/rollup/pull/4054): Add to `UNUSED_EXTERNAL_IMPORT` warning information about the origin of the problem (@cawa-93) +* [#4058](https://github.com/rollup/rollup/pull/4058): Add sanitizeFileName option (@guybedford) + +## 2.45.2 +*2021-04-13* + +### Bug Fixes +* Do not user a dynamic entry file name for naming a manual chunk (#4040) + +### Pull Requests +* [#4040](https://github.com/rollup/rollup/pull/4040): Prioritize manual chunk name over dynamic entry id (@lukastaegert) + +## 2.45.1 +*2021-04-10* + +### Bug Fixes +* Handle falsy return values from async plugin options hooks (#4039) + +### Pull Requests +* [#4039](https://github.com/rollup/rollup/pull/4039): Do not fail when returning null or undefined from an async options hook (@lukastaegert) + +## 2.45.0 +*2021-04-09* + +### Features +* Support private class instance methods and accessors (#4034) + +### Pull Requests +* [#4034](https://github.com/rollup/rollup/pull/4034): feat: add support for private class methods (@dnalborczyk) + +## 2.44.0 +*2021-03-29* + +### Features +* Add a new option `makeAbsoluteExternalsRelative` to opt out of renormalizing absolute external ids to relative ids (#4021) +* Extend the `resolveId` plugin hook to allow forcing or preventing renormalization of absolute external ids (#4021) +* Make the rendered code of individual modules available in the generated bundle (#4028) + +### Bug Fixes +* Handle objects with `__proto__` properties correctly (#4019) + +### Pull Requests +* [#4019](https://github.com/rollup/rollup/pull/4019): Deoptimize ObjectExpression when a `__proto__` property is present (@marijnh) +* [#4021](https://github.com/rollup/rollup/pull/4021): Improve absolute path handling (@lukastaegert) +* [#4026](https://github.com/rollup/rollup/pull/4026): chore: fix vscode launch config (change tdd to bdd) (@jameslahm) +* [#4027](https://github.com/rollup/rollup/pull/4027): Post comment for PRs from forks (@lukastaegert) +* [#4028](https://github.com/rollup/rollup/pull/4028): Expose rendered module code to generateBundle hook (@btd) + +## 2.43.1 +*2021-03-28* + +### Bug Fixes +* Prevent infinite recursions in certain scenarios when calling object properties (#4025) + +### Pull Requests +* [#4025](https://github.com/rollup/rollup/pull/4025): Handle recursive this mutation detection (@lukastaegert) + +## 2.43.0 +*2021-03-27* + +### Features +* Track side effects of function properties in objects for better tree-shaking (#4011) + +### Pull Requests +* [#4011](https://github.com/rollup/rollup/pull/4011): Disable pessimistic object deoptimization for calls when the called function doesn't ref this (@marijnh) +* [#4012](https://github.com/rollup/rollup/pull/4012): fix `sourcemap` reference in docs (@tjenkinson) +* [#4015](https://github.com/rollup/rollup/pull/4015): Use SIGTERM instead of SIGINT to kill test child processes in tests (@marijnh) + +## 2.42.4 +*2021-03-24* + +### Bug Fixes +* Do not discard plugin return values when using perf option (#4010) + +### Pull Requests +* [#4010](https://github.com/rollup/rollup/pull/4010): Return hook result inside promise with async timer end (@SuperOleg39) + +## 2.42.3 +*2021-03-22* + +### Bug Fixes +* Do not ignore `#__PURE__` comments in front of optional chaining expressions (#4007) + +### Pull Requests +* [#4007](https://github.com/rollup/rollup/pull/4007): Tree-shake pure call expressions with optional chaining (@lukastaegert) + +## 2.42.2 +*2021-03-22* + +### Bug Fixes +* Use correct import.meta.url in relative imports from transpiled config files (#4005) + +### Pull Requests +* [#4005](https://github.com/rollup/rollup/pull/4005): Use correct import.meta.url in config files (@lukastaegert) + +## 2.42.1 +*2021-03-20* + +### Bug Fixes +* Do not produce unhandled Promise rejections when plugins throw while using the `perf` option (#4004) + +### Pull Requests +* [#4004](https://github.com/rollup/rollup/pull/4004): Fixed unhandled promise rejections (@gluck) + +## 2.42.0 +*2021-03-19* + +### Features +* Prevent infinite loops when several plugins are using `this.resolve` in their resolveId hook (#4000) + +### Pull Requests +* [#4000](https://github.com/rollup/rollup/pull/4000): Break infinite loops in this.resolve (@lukastaegert) + +## 2.41.5 +*2021-03-18* + +### Bug Fixes +* Make sure unused property accesses of external namespaces can be tree-shaken (#4001) + +### Pull Requests +* [#4001](https://github.com/rollup/rollup/pull/4001): Do not count accessing members of an external namespace as side-effects (@lukastaegert) + +## 2.41.4 +*2021-03-16* + +### Bug Fixes +* Do not replace external namespace imports with individual named imports to avoid changing behaviour with regard to missing exports (#3999) + +### Pull Requests +* [#3999](https://github.com/rollup/rollup/pull/3999): Allow to safely probe external namespaces (@lukastaegert) + +## 2.41.3 +*2021-03-16* + +### Bug Fixes +* Always retain arguments passed to empty object pattern parameters (#3998) + +### Pull Requests +* [#3998](https://github.com/rollup/rollup/pull/3998): Do not create invalid code if a function argument is an empty object pattern (@lukastaegert) + +## 2.41.3 +*2021-03-16* + +### Bug Fixes +* Always retain arguments passed to empty object pattern parameters (#3998) + +### Pull Requests +* [#3998](https://github.com/rollup/rollup/pull/3998): Do not create invalid code if a function argument is an empty object pattern (@lukastaegert) + +## 2.41.2 +*2021-03-12* + +### Bug Fixes +* Also remove sourcemaps comments if plugins return a pre-made ast (#3987) + +### Pull Requests +* [#3987](https://github.com/rollup/rollup/pull/3987): Change removal of sourcemap comment (@yannayl) + +## 2.41.1 +*2021-03-11* + +### Pull Requests +* [#3990](https://github.com/rollup/rollup/pull/3990): Add browser sourcemap and remove log (@lukastaegert) + +## 2.41.0 +*2021-03-09* + +### Features +* Add option to `treeshake.propertyReadSideEffects` to keep all property accesses (#3985) + +### Bug Fixes +* Also respect pure comment annotations when a plugin provides an AST in the transform hook provided they use this.parse (#3981) + +### Pull Requests +* [#3981](https://github.com/rollup/rollup/pull/3981): Move pure comment annotation to Graph.contextParse (@yannayl) +* [#3985](https://github.com/rollup/rollup/pull/3985): implement --treeshake.propertyReadSideEffects=always to handle getters with side effects (@kzc) + +## 2.40.0 +*2021-02-26* + +### Features +* Make sure that entry point variable names take precedence over variable names in dependencies when deconflicting (#3977) + +### Bug Fixes +* Replace `:` in generated file names to prevent invalid files on Windows (#3972) + +### Pull Requests +* [#3972](https://github.com/rollup/rollup/pull/3972): Don't allow `:` in file names (@lukastaegert) +* [#3976](https://github.com/rollup/rollup/pull/3976): Add soft breaks to guide to improve mobile experience (@lukastaegert) +* [#3977](https://github.com/rollup/rollup/pull/3977): Reverse module deconflicting order (@lukastaegert) + +## 2.39.1 +*2021-02-23* + +### Bug Fixes +* Make sure local variables named Symbol, Object or Promise do not conflict with code generated by Rollup (#3971) + +### Pull Requests +* [#3964](https://github.com/rollup/rollup/pull/3964): Remove extra word (@jamonholmgren) +* [#3971](https://github.com/rollup/rollup/pull/3971): Avoid conflicts with local variables named Symbol, Object, Promise (@lukastaegert) + +## 2.39.0 +*2021-02-12* + +### Features +* Add "validate" option to verify generated chunks are valid JavaScript (#3952) + +### Bug Fixes +* Always add exports properties for uninitialized named exports (#3957) +* Allow using an external namespace reexport together with named exports (#3959) +* Avoid invalid generated code in certain scenarios with SystemJS exports (#3960) + +### Pull Requests +* [#3952](https://github.com/rollup/rollup/pull/3952): implement `validate` output option and `--validate` CLI option (@kzc) +* [#3956](https://github.com/rollup/rollup/pull/3956): Update dependencies, fix fsevents issue (@lukastaegert) +* [#3957](https://github.com/rollup/rollup/pull/3957): Make sure uninitialised exports turn up via .hasOwnProperty for non-ES formats (@lukastaegert) +* [#3959](https://github.com/rollup/rollup/pull/3959): Allow overriding individual exports of reexported external namespaces (@lukastaegert) +* [#3960](https://github.com/rollup/rollup/pull/3960): Make sure system exports are valid JavaScript + (@lukastaegert) + +## 2.38.5 +*2021-02-05* + +### Bug Fixes +* Prevent invalid code when simplifying assignments and delcarations (#3951) +* Prevent behaviour-changing line-breaks when simplifying assignments in return statements (#3951) +* Slightly improve white-space rendering when simplifying certain expressions (#3951) + +### Pull Requests +* [#3951](https://github.com/rollup/rollup/pull/3951): Wrap simplified assignments if necessary (@lukastaegert) + +## 2.38.4 +*2021-02-02* + +### Bug Fixes +* Do not change logic when tree-shaking declarations in if statements or loops (#3947) + +### Pull Requests +* [#3947](https://github.com/rollup/rollup/pull/3947): Do not tear apart declarations in loop or if bodies (@lukastaegert) + +## 2.38.3 +*2021-02-01* + +### Bug Fixes +* Prevent an unexpected live-binding when default exporting a synthetic named export (#3946) + +### Pull Requests +* [#3945](https://github.com/rollup/rollup/pull/3945): Upgrade chokidar and fsevents for Apple M1 compatibility (@threepointone) +* [#3946](https://github.com/rollup/rollup/pull/3946): Make sure default exports snapshot synthetic named exports (@lukastaegert) + +## 2.38.2 +*2021-01-31* + +### Bug Fixes +* Do not generate invalid code for partially tree-shaken declarations in for loops (#3943) +* Always include function bodies of functions in side-effect-free modules (#3944) + +### Pull Requests +* [#3943](https://github.com/rollup/rollup/pull/3943): Do not partially tree-shake unused declarations in for loops (@lukastaegert) +* [#3944](https://github.com/rollup/rollup/pull/3944): Correctly include functions with side effects from side-effect-free modules (@lukastaegert) + +## 2.38.1 +*2021-01-28* + +### Bug Fixes +* Fix internal error when resolving a missing entry point in the browser build (#3935) + +### Pull Requests +* [#3935](https://github.com/rollup/rollup/pull/3935): fix: remove isolated resolve() for compat with browser distribution (@cmorten and @lukastaegert) +* [#3936](https://github.com/rollup/rollup/pull/3936): Ensure test after() callback is always executed (@Benjamin-Dobell) +* [#3937](https://github.com/rollup/rollup/pull/3937): Modernize references to other software (@ludofischer) + +## 2.38.0 +*2021-01-22* + +### Features +* Entirely remove declared variables that only have an initializer side effect (#3933) + +### Pull Requests +* [#3933](https://github.com/rollup/rollup/pull/3933): Tree-shake unused declarations while keeping initializer side-effects (@lukastaegert) + +## 2.37.1 +*2021-01-20* + +### Pull Requests +* [#3929](https://github.com/rollup/rollup/pull/3929): Deduplicate acorn import (@lukastaegert) + +## 2.37.0 +*2021-01-19* + +### Features +* Always check modules for side effects that only indirectly reexport a used variable (#3840) +* Warn if a circular dependency would cause wrong execution order when preserving modules (#3840) + +### Bug Fixes +* Allow consuming synthetic exports via modules that reexport a namespace (#3894) +* Do not crash for circular default reexports (#3840) +* Do not crash for circular synthetic namespaces (#3840) +* Improve circular dependency execution order in certain scenarios (#3840) + +### Pull Requests +* [#3840](https://github.com/rollup/rollup/pull/3840): Improve circular dependency execution order (@lukastaegert) +* [#3894](https://github.com/rollup/rollup/pull/3894): Always respect synthetic namespaces in namespace reexport (@lukastaegert) + +## 2.36.2 +*2021-01-16* + +### Bug Fixes +* Fix an issue where invalid code was generated for unused assignments with side effects (#3926) + +### Pull Requests +* [#3926](https://github.com/rollup/rollup/pull/3926): Correctly simplify assignments with parentheses (@lukastaegert) + +## 2.36.1 +*2021-01-06* + +### Bug Fixes +* Solve issues that result in invalid code when partially removing assignments (#3921) + +### Pull Requests +* [#3921](https://github.com/rollup/rollup/pull/3921): Prevent invalid code when removing assignment target of side-effectful object expression (@lukastaegert) + +## 2.36.0 +*2021-01-05* + +### Features +* Support partial tree-shaking of chained assignments and unused assignment targets (#3919) + +### Pull Requests +* [#3919](https://github.com/rollup/rollup/pull/3919): Treeshake chained assignment expressions (@lukastaegert) + +## 2.35.1 +*2020-12-14* + +### Bug Fixes +* Allow closing the bundle when watching in case of generate errors by adding the bundle to the error event (#3909) +* Automatically close all bundles on generate errors when watching and using the CLI (#3909) +* Try to create remaining bundles when watching and one of them throws (#3909) + +### Pull Requests +* [#3909](https://github.com/rollup/rollup/pull/3909): Forward bundle through watch error events (@lukastaegert) + +## 2.35.0 +*2020-12-14* + +### Features +* Add `closeBundle` hook that is triggered by `bundle.close()` in the JS API (#3883) + +### Pull Requests +* [#3883](https://github.com/rollup/rollup/pull/3883): Revert pattern to folder export (@intrnl) + +## 2.34.2 +*2020-12-06* + +### Bug Fixes +* Revert pattern export change (#3898) + +### Pull Requests +* [#3898](https://github.com/rollup/rollup/pull/3898): Revert pattern to folder export (@lukastaegert) + +## 2.34.1 +*2020-12-03* + +### Bug Fixes +* Avoid Node deprecation warning by using a pattern export for nested Rollup files (#3896) + +### Pull Requests +* [#3887](https://github.com/rollup/rollup/pull/3887): Run memory leak test on all systems (@lukastaegert) +* [#3892](https://github.com/rollup/rollup/pull/3892): Add pull_request to windows github actions (@shellscape) +* [#3893](https://github.com/rollup/rollup/pull/3893): Update dependencies (@lukastaegert) +* [#3896](https://github.com/rollup/rollup/pull/3896): Replace deprecated folder package export with pattern export (@lukastaegert) + +## 2.34.0 +*2020-11-29* + +### Features +* Support RequireJS comaptible AMD ids in code-splitting builds via amd.autoId (#3867) +* Allow adding an AMD id base path (#3867) + +### Bug Fixes +* Warn when using an constant AMD id in a code-splitting build (#3867) + +### Pull Requests +* [#3867](https://github.com/rollup/rollup/pull/3867): Implement amd.autoId/amd.basePath options (@tjenkinson) + +## 2.33.3 +*2020-11-18* + +### Bug Fixes +* Do not use `.js` extension when importing AMD files from a UMD bundle (#3872) + +### Pull Requests +* [#3861](https://github.com/rollup/rollup/pull/3861): Update chat/support links (@shellscape) +* [#3872](https://github.com/rollup/rollup/pull/3872): Also removeExtensionFromRelativeAmdId in UMD finaliser (@tjenkinson) + +## 2.33.2 +*2020-11-14* + +### Bug Fixes +* Fix an issue where statements were ignored after a conditional return in a labeled statement (#3871) + +### Pull Requests +* [#3871](https://github.com/rollup/rollup/pull/3871): Correctly track label usage in try statements (@Amareis) + +## 2.33.1 +*2020-11-02* + +### Bug Fixes +* Add `syntheticNamedExports` to `this.getModuleInfo` to align with documentation (#3847) + +### Pull Requests +* [#3847](https://github.com/rollup/rollup/pull/3847): Expose syntheticNamedExports to ModuleInfo (@Amareis) +* [#3852](https://github.com/rollup/rollup/pull/3852): Fix typo on docs (@jpsc) + +## 2.33.0 +*2020-11-01* + +### Features +* Add parameter to "watchChange" hook to denote if a change was an addition, update or deletion (#3841) +* Add "closeWatcher" hook to allow plugins to clean up resources when the watcher is closed (#3841) +* Add "this.getWatchFiles" function to plugin context to get the current set of watched files (#3841) + +### Pull Requests +* [#3841](https://github.com/rollup/rollup/pull/3841): Improved watcher hooks (@Amareis) +* [#3848](https://github.com/rollup/rollup/pull/3848): Add options hook to asyncpluginhooks (@intrnl) + ## 2.32.1 *2020-10-21* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a15fd9b07a..5e03ac786a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ Anyone can file an expense. If the expense makes sense for the development of th ## Questions -If you require technical assistance, [Stackoverflow](https://stackoverflow.com/questions/tagged/rollupjs) or [Gitter](https://gitter.im/rollup/rollup) are usually the best places to start. +If you require technical assistance, [Stackoverflow](https://stackoverflow.com/questions/tagged/rollupjs) or [Discord](https://is.gd/rollup_chat) are usually the best places to start. You can also create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!). ## Credits diff --git a/LICENSE.md b/LICENSE.md index e653e14c76e..40e50892515 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -35,115 +35,7 @@ Repository: https://github.com/acornjs/acorn.git > MIT License > -> Copyright (C) 2012-2018 by various contributors (see AUTHORS) -> -> 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. - ---------------------------------------- - -## acorn-class-fields -License: MIT -By: Adrian Heine -Repository: https://github.com/acornjs/acorn-class-fields - -> Copyright (C) 2017-2018 by Adrian Heine -> -> 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. - ---------------------------------------- - -## acorn-numeric-separator -License: MIT -By: Adrian Heine -Repository: https://github.com/acornjs/acorn-numeric-separator - -> Copyright (C) 2017-2018 by Adrian Heine -> -> 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. - ---------------------------------------- - -## acorn-private-class-elements -License: MIT -By: Adrian Heine -Repository: https://github.com/acornjs/acorn-private-class-elements - -> Copyright (C) 2017-2018 by Adrian Heine -> -> 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. - ---------------------------------------- - -## acorn-static-class-features -License: MIT -By: Adrian Heine -Repository: https://github.com/acornjs/acorn-static-class-features - -> Copyright (C) 2017-2018 by Adrian Heine +> Copyright (C) 2012-2020 by various contributors (see AUTHORS) > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal @@ -172,7 +64,7 @@ Repository: https://github.com/acornjs/acorn.git > MIT License > -> Copyright (C) 2012-2018 by various contributors (see AUTHORS) +> Copyright (C) 2012-2020 by various contributors (see AUTHORS) > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal @@ -510,7 +402,7 @@ Repository: https://github.com/rich-harris/magic-string ## micromatch License: MIT -By: Jon Schlinkert, Amila Welihinda, Bogdan Chadkin, Brian Woodward, Devon Govett, Elan Shanker, Fabrício Matté, Martin Kolárik, Olsten Larck, Paul Miller, Tom Byrer, Tyler Akins, Peter Bright +By: Jon Schlinkert, Amila Welihinda, Bogdan Chadkin, Brian Woodward, Devon Govett, Elan Shanker, Fabrício Matté, Martin Kolárik, Olsten Larck, Paul Miller, Tom Byrer, Tyler Akins, Peter Bright, Kuba Juszczyk Repository: micromatch/micromatch > The MIT License (MIT) diff --git a/README.md b/README.md index 303e43db255..f9b17bb978b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# Rollup +

+ +

@@ -22,11 +24,12 @@ dependency status - - Join the chat at https://gitter.im/rollup/rollup + + Join the chat at https://is.gd/rollup_chat

+

Rollup

## Overview @@ -65,20 +68,20 @@ rollup main.js --format umd --name "myBundle" --file bundle.js Developing software is usually easier if you break your project into smaller separate pieces, since that often removes unexpected interactions and dramatically reduces the complexity of the problems you'll need to solve, and simply writing smaller projects in the first place [isn't necessarily the answer](https://medium.com/@Rich_Harris/small-modules-it-s-not-quite-that-simple-3ca532d65de4). Unfortunately, JavaScript has not historically included this capability as a core feature in the language. -This finally changed with ES modules support in JavaScript, which provides a syntax for importing and exporting functions and data so they can be shared between separate scripts. The specification is now implemented in all major browsers and in Node.js behind the --experimental-modules flag for ".mjs" files. Rollup allows you to write your code using this module system, either outputting optimized ES modules for use in these native environments, or compiling it back down to existing supported formats such as CommonJS modules, AMD modules, and IIFE-style scripts. This means that you get to *write future-proof code*, and you also get the tremendous benefits of... +This finally changed with ES modules support in JavaScript, which provides a syntax for importing and exporting functions and data so they can be shared between separate scripts. Most browsers and Node.js support ES modules. However, Node.js releases before 12.17 support ES modules only behind the `--experimental-modules` flag, and older browsers like Internet Explorer do not support ES modules at all. Rollup allows you to write your code using ES modules, and run your application even in environments that do not support ES modules natively. For environments that support them, Rollup can output optimized ES modules; for environments that don't, Rollup can compile your code to other formats such as CommonJS modules, AMD modules, and IIFE-style scripts. This means that you get to _write future-proof code_, and you also get the tremendous benefits of... ## Tree Shaking In addition to enabling the use of ES modules, Rollup also statically analyzes and optimizes the code you are importing, and will exclude anything that isn't actually used. This allows you to build on top of existing tools and modules without adding extra dependencies or bloating the size of your project. -For example, with CommonJS, the *entire tool or library must be imported*. +For example, with CommonJS, the _entire tool or library must be imported_. ```js // import the entire utils object with CommonJS -var utils = require( 'utils' ); +var utils = require('utils'); var query = 'Rollup'; // use the ajax method of the utils object -utils.ajax( 'https://api.example.com?search=' + query ).then( handleResponse ); +utils.ajax('https://api.example.com?search=' + query).then(handleResponse); ``` But with ES modules, instead of importing the whole `utils` object, we can just import the one `ajax` function we need: @@ -88,7 +91,7 @@ But with ES modules, instead of importing the whole `utils` object, we can just import { ajax } from 'utils'; var query = 'Rollup'; // call the ajax function -ajax( 'https://api.example.com?search=' + query ).then( handleResponse ); +ajax('https://api.example.com?search=' + query).then(handleResponse); ``` Because Rollup includes the bare minimum, it results in lighter, faster, and less complicated libraries and applications. Since this approach is based on explicit `import` and `export` statements, it is vastly more effective than simply running an automated minifier to detect unused variables in the compiled output code. @@ -101,21 +104,19 @@ Rollup can import existing CommonJS modules [through a plugin](https://github.co ### Publishing ES Modules -To make sure your ES modules are immediately usable by tools that work with CommonJS such as Node.js and webpack, you can use Rollup to compile to UMD or CommonJS format, and then point to that compiled version with the `main` property in your `package.json` file. If your `package.json` file also has a `module` field, ES-module-aware tools like Rollup and [webpack 2](https://webpack.js.org/) will [import the ES module version](https://github.com/rollup/rollup/wiki/pkg.module) directly. +To make sure your ES modules are immediately usable by tools that work with CommonJS such as Node.js and webpack, you can use Rollup to compile to UMD or CommonJS format, and then point to that compiled version with the `main` property in your `package.json` file. If your `package.json` file also has a `module` field, ES-module-aware tools like Rollup and [webpack](https://webpack.js.org/) will [import the ES module version](https://github.com/rollup/rollup/wiki/pkg.module) directly. ## Contributors This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. - ## Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/rollup#backer)] - ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/rollup#sponsor)] @@ -131,8 +132,6 @@ Support this project by becoming a sponsor. Your logo will show up here with a l - - ## License [MIT](https://github.com/rollup/rollup/blob/master/LICENSE.md) diff --git a/browser/crypto.ts b/browser/crypto.ts index 294dc57ff80..c104e6cca8b 100644 --- a/browser/crypto.ts +++ b/browser/crypto.ts @@ -1,3 +1,6 @@ import sha256 from 'hash.js/lib/hash/sha/256'; -export const createHash = () => sha256(); +export const createHash = (): { + digest: (format: string) => string; + update: (data: unknown) => void; +} => sha256(); diff --git a/browser/error.ts b/browser/error.ts new file mode 100644 index 00000000000..c594d9bb8a9 --- /dev/null +++ b/browser/error.ts @@ -0,0 +1,9 @@ +import { error } from '../src/utils/error'; + +export const throwNoFileSystem = (method: string) => (): never => { + error({ + code: 'NO_FS_IN_BROWSER', + message: `Cannot access the file system (via "${method}") when using the browser build of Rollup. Make sure you supply a plugin with custom resolveId and load hooks to Rollup.`, + url: 'https://rollupjs.org/guide/en/#a-simple-example' + }); +}; diff --git a/browser/fs.ts b/browser/fs.ts index fbd18d02214..31337a88016 100644 --- a/browser/fs.ts +++ b/browser/fs.ts @@ -1,14 +1,4 @@ -const nope = (method: string) => (..._args: any[]): never => { - throw Object.assign( - new Error( - `Cannot access the file system (via "fs.${method}") when using the browser build of Rollup. Make sure you supply a plugin with custom resolveId and load hooks to Rollup.` - ), - { code: 'NO_FS_IN_BROWSER', url: 'https://rollupjs.org/guide/en/#a-simple-example' } - ); -}; +import { throwNoFileSystem } from './error'; -export const lstatSync = nope('lstatSync'); -export const readdirSync = nope('readdirSync'); -export const readFile = nope('readFile'); -export const realpathSync = nope('realpathSync'); -export const writeFile = nope('writeFile'); +export const readFile = throwNoFileSystem('fs.readFile'); +export const writeFile = throwNoFileSystem('fs.writeFile'); diff --git a/browser/path.ts b/browser/path.ts index ecae1fa030f..f0e44ade1d0 100644 --- a/browser/path.ts +++ b/browser/path.ts @@ -1,24 +1,24 @@ export const absolutePath = /^(?:\/|(?:[A-Za-z]:)?[\\|/])/; export const relativePath = /^\.?\.\//; -export function isAbsolute(path: string) { +export function isAbsolute(path: string): boolean { return absolutePath.test(path); } -export function isRelative(path: string) { +export function isRelative(path: string): boolean { return relativePath.test(path); } -export function normalize(path: string) { +export function normalize(path: string): string { return path.replace(/\\/g, '/'); } -export function basename(path: string) { - return path.split(/(\/|\\)/).pop(); +export function basename(path: string): string { + return path.split(/[/\\]/).pop() || ''; } -export function dirname(path: string) { - const match = /(\/|\\)[^/\\]*$/.exec(path); +export function dirname(path: string): string { + const match = /[/\\][^/\\]*$/.exec(path); if (!match) return '.'; const dir = path.slice(0, -match[0].length); @@ -27,13 +27,13 @@ export function dirname(path: string) { return dir ? dir : '/'; } -export function extname(path: string) { +export function extname(path: string): string { const match = /\.[^.]+$/.exec(basename(path)!); if (!match) return ''; return match[0]; } -export function relative(from: string, to: string) { +export function relative(from: string, to: string): string { const fromParts = from.split(/[/\\]/).filter(Boolean); const toParts = to.split(/[/\\]/).filter(Boolean); @@ -57,10 +57,14 @@ export function relative(from: string, to: string) { return toParts.join('/'); } -export function resolve(...paths: string[]) { - let resolvedParts = paths.shift()!.split(/[/\\]/); +export function resolve(...paths: string[]): string { + const firstPathSegment = paths.shift(); + if (!firstPathSegment) { + return '/'; + } + let resolvedParts = firstPathSegment.split(/[/\\]/); - paths.forEach(path => { + for (const path of paths) { if (isAbsolute(path)) { resolvedParts = path.split(/[/\\]/); } else { @@ -73,9 +77,9 @@ export function resolve(...paths: string[]) { } } - resolvedParts.push.apply(resolvedParts, parts); + resolvedParts.push(...parts); } - }); + } return resolvedParts.join('/'); } diff --git a/browser/resolveId.ts b/browser/resolveId.ts new file mode 100644 index 00000000000..59b57b0d584 --- /dev/null +++ b/browser/resolveId.ts @@ -0,0 +1,32 @@ +import { CustomPluginOptions, Plugin, ResolvedId, ResolveIdResult } from '../src/rollup/types'; +import { PluginDriver } from '../src/utils/PluginDriver'; +import { resolveIdViaPlugins } from '../src/utils/resolveIdViaPlugins'; +import { throwNoFileSystem } from './error'; + +export async function resolveId( + source: string, + importer: string | undefined, + _preserveSymlinks: boolean, + pluginDriver: PluginDriver, + moduleLoaderResolveId: ( + source: string, + importer: string | undefined, + customOptions: CustomPluginOptions | undefined, + skip: { importer: string | undefined; plugin: Plugin; source: string }[] | null + ) => Promise, + skip: { importer: string | undefined; plugin: Plugin; source: string }[] | null, + customOptions: CustomPluginOptions | undefined +): Promise { + const pluginResult = await resolveIdViaPlugins( + source, + importer, + pluginDriver, + moduleLoaderResolveId, + skip, + customOptions + ); + if (pluginResult == null) { + throwNoFileSystem('path.resolve'); + } + return pluginResult; +} diff --git a/build-plugins/add-cli-entry.js b/build-plugins/add-cli-entry.js index 9d9c681b675..dbb8446c8f6 100644 --- a/build-plugins/add-cli-entry.js +++ b/build-plugins/add-cli-entry.js @@ -2,15 +2,15 @@ import MagicString from 'magic-string'; export default function addCliEntry() { return { - name: 'add-cli-entry', buildStart() { this.emitFile({ - type: 'chunk', - id: 'cli/cli.ts', fileName: 'bin/rollup', - preserveSignature: false + id: 'cli/cli.ts', + preserveSignature: false, + type: 'chunk' }); }, + name: 'add-cli-entry', renderChunk(code, chunkInfo) { if (chunkInfo.fileName === 'bin/rollup') { const magicString = new MagicString(code); diff --git a/build-plugins/conditional-fsevents-import.js b/build-plugins/conditional-fsevents-import.js index 38d08dcf99d..d4acf2bd3c9 100644 --- a/build-plugins/conditional-fsevents-import.js +++ b/build-plugins/conditional-fsevents-import.js @@ -6,6 +6,11 @@ const REPLACEMENT = "require('../../../src/watch/fsevents-importer').getFsEvents export default function conditionalFsEventsImport() { let transformed = false; return { + buildEnd(error) { + if (!(error || transformed)) { + throw new Error('Could not find "fsevents-handler.js", was the file renamed?'); + } + }, name: 'conditional-fs-events-import', transform(code, id) { if (id.endsWith('fsevents-handler.js')) { @@ -22,11 +27,6 @@ export default function conditionalFsEventsImport() { ); return { code: magicString.toString(), map: magicString.generateMap({ hires: true }) }; } - }, - buildEnd() { - if (!transformed) { - throw new Error('Could not find "fsevents-handler.js", was the file renamed?'); - } } }; } diff --git a/build-plugins/emit-module-package-file.js b/build-plugins/emit-module-package-file.js index 0cdf130a02a..c6a41ddfd04 100644 --- a/build-plugins/emit-module-package-file.js +++ b/build-plugins/emit-module-package-file.js @@ -1,8 +1,8 @@ export default function emitModulePackageFile() { return { - name: 'emit-module-package-file', generateBundle() { - this.emitFile({ type: 'asset', fileName: 'package.json', source: `{"type":"module"}` }); - } + this.emitFile({ fileName: 'package.json', source: `{"type":"module"}`, type: 'asset' }); + }, + name: 'emit-module-package-file' }; } diff --git a/build-plugins/esm-dynamic-import.js b/build-plugins/esm-dynamic-import.js index 5bc8b8ea444..0e2a8e63478 100644 --- a/build-plugins/esm-dynamic-import.js +++ b/build-plugins/esm-dynamic-import.js @@ -1,19 +1,19 @@ export default function addBinShebangAndEsmImport() { let importFound = false; return { - name: 'esm-dynamic-import', - renderDynamicImport({ moduleId }) { - importFound = true; - if (moduleId.endsWith('loadConfigFile.ts')) { - return { left: 'import(', right: ')' }; - } - }, generateBundle() { if (!importFound) { throw new Error( 'Could not find dynamic import in "loadConfigFile.ts", was the file renamed?' ); } + }, + name: 'esm-dynamic-import', + renderDynamicImport({ moduleId }) { + importFound = true; + if (moduleId.endsWith('loadConfigFile.ts')) { + return { left: 'import(', right: ')' }; + } } }; } diff --git a/build-plugins/replace-browser-modules.js b/build-plugins/replace-browser-modules.js new file mode 100644 index 00000000000..9e004c5ffd9 --- /dev/null +++ b/build-plugins/replace-browser-modules.js @@ -0,0 +1,27 @@ +import path from 'path'; + +const ID_CRYPTO = path.resolve('src/utils/crypto'); +const ID_FS = path.resolve('src/utils/fs'); +const ID_PATH = path.resolve('src/utils/path'); +const ID_RESOLVEID = path.resolve('src/utils/resolveId'); + +export default function replaceBrowserModules() { + return { + name: 'replace-browser-modules', + resolveId: (source, importee) => { + if (importee && source[0] === '.') { + const resolved = path.join(path.dirname(importee), source); + switch (resolved) { + case ID_CRYPTO: + return path.resolve('browser/crypto.ts'); + case ID_FS: + return path.resolve('browser/fs.ts'); + case ID_PATH: + return path.resolve('browser/path.ts'); + case ID_RESOLVEID: + return path.resolve('browser/resolveId.ts'); + } + } + } + }; +} diff --git a/cli/help.md b/cli/help.md index 40e3d3e7911..a6f24792880 100644 --- a/cli/help.md +++ b/cli/help.md @@ -20,6 +20,8 @@ Basic options: -v, --version Show version number -w, --watch Watch files in bundle and rebuild on changes --amd.id ID for AMD module (default is anonymous) +--amd.autoId Generate the AMD ID based off the chunk name +--amd.basePath Path to prepend to auto generated AMD ID --amd.define Function to use in place of `define` --assetFileNames Name pattern for emitted assets --banner Code to insert at top of bundle (outside wrapper) @@ -49,6 +51,7 @@ Basic options: --preserveModules Preserve module structure --preserveModulesRoot Put preserved modules under this path at root level --preserveSymlinks Do not follow symlinks when resolving files +--no-sanitizeFileName Do not replace invalid characters in file names --shimMissingExports Create shim variables for missing exports --silent Don't print warnings --sourcemapExcludeSources Do not include source code in source maps @@ -70,6 +73,7 @@ Basic options: --watch.skipWrite Do not write files to disk when watching --watch.exclude Exclude files from being watched --watch.include Limit watching to specified files +--validate Validate output Examples: diff --git a/cli/logging.ts b/cli/logging.ts index 329db43e11f..250a91e7a03 100644 --- a/cli/logging.ts +++ b/cli/logging.ts @@ -11,7 +11,7 @@ if (process.env.FORCE_COLOR === '0' || process.env.NO_COLOR) { // log to stderr to keep `rollup main.js > bundle.js` from breaking export const stderr = console.error.bind(console); -export function handleError(err: RollupError, recover = false) { +export function handleError(err: RollupError, recover = false): void { let description = err.message || err; if (err.name) description = `${err.name}: ${description}`; const message = (err.plugin ? `(plugin ${err.plugin}) ${description}` : description) || err; diff --git a/cli/run/batchWarnings.ts b/cli/run/batchWarnings.ts index 1fe3d03ae30..64f0a6cc758 100644 --- a/cli/run/batchWarnings.ts +++ b/cli/run/batchWarnings.ts @@ -1,6 +1,7 @@ import { bold, gray, yellow } from 'colorette'; import { RollupWarning } from '../../src/rollup/types'; import { getOrCreate } from '../../src/utils/getOrCreate'; +import { printQuotedStringList } from '../../src/utils/printStringList'; import relativeId from '../../src/utils/relativeId'; import { stderr } from '../logging'; @@ -11,20 +12,12 @@ export interface BatchWarnings { readonly warningOccurred: boolean; } -export default function batchWarnings() { +export default function batchWarnings(): BatchWarnings { let count = 0; let deferredWarnings = new Map(); let warningOccurred = false; return { - get count() { - return count; - }, - - get warningOccurred() { - return warningOccurred; - }, - add: (warning: RollupWarning) => { count += 1; warningOccurred = true; @@ -41,7 +34,7 @@ export default function batchWarnings() { const id = (warning.loc && warning.loc.file) || warning.id; if (id) { const loc = warning.loc - ? `${relativeId(id)}: (${warning.loc.line}:${warning.loc.column})` + ? `${relativeId(id)} (${warning.loc.line}:${warning.loc.column})` : relativeId(id); stderr(bold(relativeId(loc))); @@ -51,6 +44,10 @@ export default function batchWarnings() { } }, + get count() { + return count; + }, + flush: () => { if (count === 0) return; @@ -64,6 +61,10 @@ export default function batchWarnings() { deferredWarnings = new Map(); count = 0; + }, + + get warningOccurred() { + return warningOccurred; } }; } @@ -71,24 +72,19 @@ export default function batchWarnings() { const immediateHandlers: { [code: string]: (warning: RollupWarning) => void; } = { - UNKNOWN_OPTION: warning => { - title(`You have passed an unrecognized option`); - stderr(warning.message); - }, - MISSING_NODE_BUILTINS: warning => { title(`Missing shims for Node.js built-ins`); - const detail = - warning.modules!.length === 1 - ? `'${warning.modules![0]}'` - : `${warning - .modules!.slice(0, -1) - .map((name: string) => `'${name}'`) - .join(', ')} and '${warning.modules!.slice(-1)}'`; stderr( - `Creating a browser bundle that depends on ${detail}. You might need to include https://github.com/ionic-team/rollup-plugin-node-polyfills` + `Creating a browser bundle that depends on ${printQuotedStringList( + warning.modules! + )}. You might need to include https://github.com/ionic-team/rollup-plugin-node-polyfills` ); + }, + + UNKNOWN_OPTION: warning => { + title(`You have passed an unrecognized option`); + stderr(warning.message); } }; @@ -162,11 +158,11 @@ const deferredHandlers: { title(`Conflicting re-exports`); for (const warning of warnings) { stderr( - `${bold(relativeId(warning.reexporter!))} re-exports '${ + `"${bold(relativeId(warning.reexporter!))}" re-exports "${ warning.name - }' from both ${relativeId(warning.sources![0])} and ${relativeId( + }" from both "${relativeId(warning.sources![0])}" and "${relativeId( warning.sources![1] - )} (will be ignored)` + )}" (will be ignored)` ); } }, @@ -207,16 +203,14 @@ const deferredHandlers: { title(`Broken sourcemap`); info('https://rollupjs.org/guide/en/#warning-sourcemap-is-likely-to-be-incorrect'); - const plugins = Array.from(new Set(warnings.map(w => w.plugin).filter(Boolean))); - const detail = - plugins.length > 1 - ? ` (such as ${plugins - .slice(0, -1) - .map(p => `'${p}'`) - .join(', ')} and '${plugins.slice(-1)}')` - : ` (such as '${plugins[0]}')`; - - stderr(`Plugins that transform code${detail} should generate accompanying sourcemaps`); + const plugins = [ + ...new Set(warnings.map(warning => warning.plugin).filter(Boolean)) + ] as string[]; + stderr( + `Plugins that transform code (such as ${printQuotedStringList( + plugins + )}) should generate accompanying sourcemaps` + ); }, THIS_IS_UNDEFINED(warnings) { diff --git a/cli/run/build.ts b/cli/run/build.ts index 954dba4c6e2..c5fab831470 100644 --- a/cli/run/build.ts +++ b/cli/run/build.ts @@ -24,9 +24,7 @@ export default async function build( } else if (inputOptions.input instanceof Array) { inputFiles = inputOptions.input.join(', '); } else if (typeof inputOptions.input === 'object' && inputOptions.input !== null) { - inputFiles = Object.keys(inputOptions.input) - .map(name => (inputOptions.input as Record)[name]) - .join(', '); + inputFiles = Object.values(inputOptions.input).join(', '); } stderr(cyan(`\n${bold(inputFiles!)} → ${bold(files.join(', '))}...`)); } @@ -53,7 +51,7 @@ export default async function build( } } if (outputs.length > 1) process.stdout.write(`\n${cyan(bold(`//→ ${file.fileName}:`))}\n`); - process.stdout.write(source); + process.stdout.write(source as Buffer); } if (!silent) { warnings.flush(); @@ -62,6 +60,7 @@ export default async function build( } await Promise.all(outputOptions.map(bundle.write)); + await bundle.close(); if (!silent) { warnings.flush(); stderr(green(`created ${bold(files.join(', '))} in ${bold(ms(Date.now() - start))}`)); diff --git a/cli/run/commandPlugins.ts b/cli/run/commandPlugins.ts index 503cf41c7a1..270f998a206 100644 --- a/cli/run/commandPlugins.ts +++ b/cli/run/commandPlugins.ts @@ -5,7 +5,7 @@ import { waitForInputPlugin } from './waitForInput'; export function addCommandPluginsToInputOptions( inputOptions: InputOptions, - command: any, + command: Record, pluginOption = 'plugin', extension = '' ) { @@ -53,7 +53,7 @@ function loadAndRegisterPlugin(inputOptions: InputOptions, pluginText: string) { // -p "{transform(c,i){...}}" plugin = new Function('return ' + pluginText); } else { - const match = pluginText.match(/^([@.\/\\\w|^{}-]+)(=(.*))?$/); + const match = pluginText.match(/^([@./\\\w|^{}-]+)(=(.*))?$/); if (match) { // -p plugin // -p plugin=arg @@ -62,7 +62,7 @@ function loadAndRegisterPlugin(inputOptions: InputOptions, pluginText: string) { } else { throw new Error(`Invalid --plugin argument format: ${JSON.stringify(pluginText)}`); } - if (!/^\.|^rollup-plugin-|[@\/\\]/.test(pluginText)) { + if (!/^\.|^rollup-plugin-|[@/\\]/.test(pluginText)) { // Try using plugin prefix variations first if applicable. // Prefix order is significant - left has higher precedence. for (const prefix of ['@rollup/plugin-', 'rollup-plugin-']) { diff --git a/cli/run/index.ts b/cli/run/index.ts index 086b325d536..e20a6c8db37 100644 --- a/cli/run/index.ts +++ b/cli/run/index.ts @@ -8,7 +8,7 @@ import { getConfigPath } from './getConfigPath'; import loadAndParseConfigFile from './loadConfigFile'; import loadConfigFromCommand from './loadConfigFromCommand'; -export default async function runRollup(command: any) { +export default async function runRollup(command: Record): Promise { let inputSource; if (command._.length > 0) { if (command.input) { diff --git a/cli/run/loadConfigFile.ts b/cli/run/loadConfigFile.ts index 01ac46ceb92..16a900f36af 100644 --- a/cli/run/loadConfigFile.ts +++ b/cli/run/loadConfigFile.ts @@ -1,7 +1,7 @@ -import { bold } from 'colorette'; import * as fs from 'fs'; import * as path from 'path'; import { pathToFileURL } from 'url'; +import { bold } from 'colorette'; import * as rollup from '../../src/node-entry'; import { MergedRollupOptions } from '../../src/rollup/types'; import { error } from '../../src/utils/error'; @@ -83,7 +83,20 @@ async function getDefaultFromTranspiledConfigFile( output: [{ code }] } = await bundle.generate({ exports: 'named', - format: 'cjs' + format: 'cjs', + plugins: [ + { + name: 'transpile-import-meta', + resolveImportMeta(property, { moduleId }) { + if (property === 'url') { + return `'${pathToFileURL(moduleId).href}'`; + } + if (property == null) { + return `{url:'${pathToFileURL(moduleId).href}'}`; + } + } + } + ] }); return loadConfigFromBundledFile(fileName, code); } @@ -91,7 +104,7 @@ async function getDefaultFromTranspiledConfigFile( async function loadConfigFromBundledFile(fileName: string, bundledCode: string) { const resolvedFileName = fs.realpathSync(fileName); const extension = path.extname(resolvedFileName); - const defaultLoader = require.extensions[extension]!; + const defaultLoader = require.extensions[extension]; require.extensions[extension] = (module: NodeModule, requiredFileName: string) => { if (requiredFileName === resolvedFileName) { (module as NodeModuleWithCompile)._compile(bundledCode, requiredFileName); diff --git a/cli/run/loadConfigFromCommand.ts b/cli/run/loadConfigFromCommand.ts index 424a484a254..c13879076d3 100644 --- a/cli/run/loadConfigFromCommand.ts +++ b/cli/run/loadConfigFromCommand.ts @@ -5,7 +5,7 @@ import { addCommandPluginsToInputOptions } from './commandPlugins'; import { stdinName } from './stdin'; export default function loadConfigFromCommand( - command: any + command: Record ): { options: MergedRollupOptions[]; warnings: BatchWarnings } { const warnings = batchWarnings(); if (!command.input && (command.stdin || !process.stdin.isTTY)) { diff --git a/cli/run/resetScreen.ts b/cli/run/resetScreen.ts index c057a84e9e6..39fc53c70b3 100644 --- a/cli/run/resetScreen.ts +++ b/cli/run/resetScreen.ts @@ -3,7 +3,10 @@ import { stderr } from '../logging'; const CLEAR_SCREEN = '\u001Bc'; -export function getResetScreen(configs: MergedRollupOptions[], allowClearScreen: boolean) { +export function getResetScreen( + configs: MergedRollupOptions[], + allowClearScreen: boolean | undefined +): (heading: string) => void { let clearScreen = allowClearScreen; for (const config of configs) { if (config.watch && config.watch.clearScreen === false) { diff --git a/cli/run/stdin.ts b/cli/run/stdin.ts index 3cd6ff16725..c4c0b853435 100644 --- a/cli/run/stdin.ts +++ b/cli/run/stdin.ts @@ -4,19 +4,19 @@ export const stdinName = '-'; let stdinResult: Promise | null = null; -export function stdinPlugin(arg: any): Plugin { +export function stdinPlugin(arg: unknown): Plugin { const suffix = typeof arg == 'string' && arg.length ? '.' + arg : ''; return { + load(id) { + if (id === stdinName || id.startsWith(stdinName + '.')) { + return stdinResult || (stdinResult = readStdin()); + } + }, name: 'stdin', resolveId(id) { if (id === stdinName) { return id + suffix; } - }, - load(id) { - if (id === stdinName || id.startsWith(stdinName + '.')) { - return stdinResult || (stdinResult = readStdin()); - } } }; } diff --git a/cli/run/timings.ts b/cli/run/timings.ts index 23c967dc921..c298a345f87 100644 --- a/cli/run/timings.ts +++ b/cli/run/timings.ts @@ -2,7 +2,7 @@ import { bold, underline } from 'colorette'; import prettyBytes from 'pretty-bytes'; import { SerializedTimings } from '../../src/rollup/types'; -export function printTimings(timings: SerializedTimings) { +export function printTimings(timings: SerializedTimings): void { Object.keys(timings).forEach(label => { const appliedColor = label[0] === '#' ? (label[1] !== '#' ? underline : bold) : (text: string) => text; diff --git a/cli/run/waitForInput.ts b/cli/run/waitForInput.ts index 5c48a3f5396..e590419d86e 100644 --- a/cli/run/waitForInput.ts +++ b/cli/run/waitForInput.ts @@ -1,10 +1,10 @@ import { bold } from 'colorette'; -import { NormalizedInputOptions, PluginContext } from '../../src/rollup/types'; +import { PluginContext } from 'rollup'; +import { NormalizedInputOptions, Plugin } from '../../src/rollup/types'; import { stderr } from '../logging'; -export function waitForInputPlugin() { +export function waitForInputPlugin(): Plugin { return { - name: 'wait-for-input', async buildStart(this: PluginContext, options: NormalizedInputOptions) { const inputSpecifiers = Array.isArray(options.input) ? options.input @@ -24,6 +24,7 @@ export function waitForInputPlugin() { } break; } - } + }, + name: 'wait-for-input' }; } diff --git a/cli/run/watch-cli.ts b/cli/run/watch-cli.ts index 1e5aeff9ed7..39aad7ed083 100644 --- a/cli/run/watch-cli.ts +++ b/cli/run/watch-cli.ts @@ -1,7 +1,7 @@ +import fs from 'fs'; import chokidar from 'chokidar'; import { bold, cyan, green, underline } from 'colorette'; import dateTime from 'date-time'; -import fs from 'fs'; import ms from 'pretty-ms'; import onExit from 'signal-exit'; import * as rollup from '../../src/node-entry'; @@ -15,7 +15,7 @@ import loadConfigFromCommand from './loadConfigFromCommand'; import { getResetScreen } from './resetScreen'; import { printTimings } from './timings'; -export async function watch(command: any) { +export async function watch(command: Record): Promise { process.env.ROLLUP_WATCH = 'true'; const isTTY = process.stderr.isTTY; const silent = command.silent; @@ -32,7 +32,7 @@ export async function watch(command: any) { process.stdin.resume(); } - if (configFile) { + async function loadConfigFromFileAndTrack(configFile: string) { let reloadingConfig = false; let aborted = false; let configFileData: string | null = null; @@ -42,7 +42,7 @@ export async function watch(command: any) { async function reloadConfigFile() { try { - const newConfigFileData = fs.readFileSync(configFile!, 'utf-8'); + const newConfigFileData = fs.readFileSync(configFile, 'utf-8'); if (newConfigFileData === configFileData) { return; } @@ -55,7 +55,7 @@ export async function watch(command: any) { } configFileData = newConfigFileData; reloadingConfig = true; - ({ options: configs, warnings } = await loadAndParseConfigFile(configFile!, command)); + ({ options: configs, warnings } = await loadAndParseConfigFile(configFile, command)); reloadingConfig = false; if (aborted) { aborted = false; @@ -72,12 +72,15 @@ export async function watch(command: any) { handleError(err, true); } } + } + + if (configFile) { + await loadConfigFromFileAndTrack(configFile); } else { ({ options: configs, warnings } = await loadConfigFromCommand(command)); start(configs); } - // tslint:disable-next-line:no-unnecessary-type-assertion const resetScreen = getResetScreen(configs!, isTTY); function start(configs: MergedRollupOptions[]) { @@ -106,9 +109,7 @@ export async function watch(command: any) { if (typeof input !== 'string') { input = Array.isArray(input) ? input.join(', ') - : Object.keys(input as Record) - .map(key => (input as Record)[key]) - .join(', '); + : Object.values(input as Record).join(', '); } stderr( cyan(`bundles ${bold(input)} → ${bold(event.output.map(relativeId).join(', '))}...`) @@ -136,6 +137,10 @@ export async function watch(command: any) { stderr(`\n[${dateTime()}] waiting for changes...`); } } + + if ('result' in event && event.result) { + event.result.close().catch(error => handleError(error, true)); + } }); } diff --git a/docs/01-command-line-reference.md b/docs/01-command-line-reference.md index 98f8da1c092..fdd17064b4c 100755 --- a/docs/01-command-line-reference.md +++ b/docs/01-command-line-reference.md @@ -85,6 +85,7 @@ export default { // can be an array (for multiple inputs) sourcemapExcludeSources, sourcemapFile, sourcemapPathTransform, + validate, // danger zone amd, @@ -96,6 +97,7 @@ export default { // can be an array (for multiple inputs) namespaceToStringTag, noConflict, preferConst, + sanitizeFileName, strict, systemNullSetters }, @@ -200,6 +202,33 @@ export default commandLineArgs => { } ``` +#### Config Intellisense + +Since Rollup ships with TypeScript typings, you can leverage your IDE's intellisense with jsdoc type hints: + +```javascript +// rollup.config.js +/** + * @type {import('rollup').RollupOptions} + */ +const config = { + // ... +} + +export default config +``` + +Alternatively you can use the helper which should provide intellisense without the need for jsdoc annotations:defineConfig + +```javascript +// rollup.config.js +import { defineConfig } from 'rollup' + +export default defineConfig({ + // ... +}) +``` + ### Differences to the JavaScript API While config files provide an easy way to configure Rollup, they also limit how Rollup can be invoked and where configuration is taken from. Especially if you are rebundling Rollup in another build tool or want to integrate it into an advanced build process, it may be better to directly invoke Rollup programmatically from your scripts. @@ -280,6 +309,8 @@ Many options have command line equivalents. In those cases, any arguments passed -v, --version Show version number -w, --watch Watch files in bundle and rebuild on changes --amd.id ID for AMD module (default is anonymous) +--amd.autoId Generate the AMD ID based off the chunk name +--amd.basePath Path to prepend to auto generated AMD ID --amd.define Function to use in place of `define` --assetFileNames Name pattern for emitted assets --banner Code to insert at top of bundle (outside wrapper) @@ -309,6 +340,7 @@ Many options have command line equivalents. In those cases, any arguments passed --preserveModules Preserve module structure --preserveModulesRoot Put preserved modules under this path at root level --preserveSymlinks Do not follow symlinks when resolving files +--no-sanitizeFileName Do not replace invalid characters in file names --shimMissingExports Create shim variables for missing exports --silent Don't print warnings --sourcemapExcludeSources Do not include source code in source maps @@ -330,6 +362,7 @@ Many options have command line equivalents. In those cases, any arguments passed --watch.skipWrite Do not write files to disk when watching --watch.exclude Exclude files from being watched --watch.include Limit watching to specified files +--validate Validate output ``` The flags listed below are only available via the command line interface. All other flags correspond to and override their config file equivalents, see the [big list of options](guide/en/#big-list-of-options) for details. diff --git a/docs/02-javascript-api.md b/docs/02-javascript-api.md index 9704b3f1fa1..725e2f5d5d7 100755 --- a/docs/02-javascript-api.md +++ b/docs/02-javascript-api.md @@ -1,3 +1,4 @@ + --- title: JavaScript API --- @@ -10,6 +11,8 @@ The `rollup.rollup` function receives an input options object as parameter and r On a `bundle` object, you can call `bundle.generate` multiple times with different output options objects to generate different bundles in-memory. If you directly want to write them to disk, use `bundle.write` instead. +Once you're finished with the `bundle` object, you should call `bundle.close()`, which will let plugins clean up their external processes or services via the [`closeBundle`](guide/en/#closebundle) hook. + ```javascript const rollup = require('rollup'); @@ -57,6 +60,7 @@ async function build() { // removedExports: string[]; // exported variable names that were removed // renderedLength: number; // the length of the remaining code in this module // originalLength: number; // the original length of the code in this module + // code: string | null; // remaining code in this module // }; // }, // name: string // the name of this chunk as used in naming patterns @@ -69,6 +73,9 @@ async function build() { // or write the bundle to disk await bundle.write(outputOptions); + + // closes the bundle + await bundle.close(); } build(); @@ -82,7 +89,7 @@ The `inputOptions` object can contain the following properties (see the [big lis const inputOptions = { // core input options external, - input, // condtionally required + input, // conditionally required plugins, // advanced input options @@ -143,6 +150,7 @@ const outputOptions = { sourcemapExcludeSources, sourcemapFile, sourcemapPathTransform, + validate, // danger zone amd, @@ -153,6 +161,7 @@ const outputOptions = { namespaceToStringTag, noConflict, preferConst, + sanitizeFileName, strict, systemNullSetters }; @@ -160,7 +169,7 @@ const outputOptions = { ### rollup.watch -Rollup also provides a `rollup.watch` function that rebuilds your bundle when it detects that the individual modules have changed on disk. It is used internally when you run Rollup from the command line with the `--watch` flag. +Rollup also provides a `rollup.watch` function that rebuilds your bundle when it detects that the individual modules have changed on disk. It is used internally when you run Rollup from the command line with the `--watch` flag. Note that when using watch mode via the JavaScript API, it is your responsibility to call `event.result.close()` in response to the `BUNDLE_END` event to allow plugins to clean up resources in the [`closeBundle`](guide/en/#closebundle) hook, see below. ```js const rollup = require('rollup'); @@ -172,9 +181,36 @@ watcher.on('event', event => { // event.code can be one of: // START — the watcher is (re)starting // BUNDLE_START — building an individual bundle + // * event.input will be the input options object if present + // * event.outputFiles cantains an array of the "file" or + // "dir" option values of the generated outputs // BUNDLE_END — finished building a bundle + // * event.input will be the input options object if present + // * event.outputFiles cantains an array of the "file" or + // "dir" option values of the generated outputs + // * event.duration is the build duration in milliseconds + // * event.result contains the bundle object that can be + // used to generate additional outputs by calling + // bundle.generate or bundle.write. This is especially + // important when the watch.skipWrite option is used. + // You should call "event.result.close()" once you are done + // generating outputs, or if you do not generate outputs. + // This will allow plugins to clean up resources via the + // "closeBundle" hook. // END — finished building all bundles // ERROR — encountered an error while bundling + // * event.error contains the error that was thrown + // * event.result is null for build errors and contains the + // bundle object for output generation errors. As with + // "BUNDLE_END", you should call "event.result.close()" if + // present once you are done. +}); + +// This will make sure that bundles are properly closed after each run +watcher.on('event', ({ result }) => { + if (result) { + result.close(); + } }); // stop watching diff --git a/docs/05-plugin-development.md b/docs/05-plugin-development.md index 80e26ff4745..a8e3086d194 100644 --- a/docs/05-plugin-development.md +++ b/docs/05-plugin-development.md @@ -8,7 +8,7 @@ A Rollup plugin is an object with one or more of the [properties](guide/en/#prop Plugins allow you to customise Rollup's behaviour by, for example, transpiling code before bundling, or finding third-party modules in your `node_modules` folder. For an example on how to use them, see [Using plugins](guide/en/#using-plugins). -A List of Plugins may be found at https://github.com/rollup/awesome. If you would like to make a suggestion for a plugin, please submit a Pull Request. +A List of Plugins may be found at [github.com/rollup/awesome](https://github.com/rollup/awesome). If you would like to make a suggestion for a plugin, please submit a Pull Request. ### A Simple Example @@ -72,7 +72,9 @@ To interact with the build process, your plugin object includes 'hooks'. Hooks a * `sequential`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will wait until the current hook is resolved. * `parallel`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will be run in parallel and not wait for the current hook. -Build hooks are run during the build phase, which is triggered by `rollup.rollup(inputOptions)`. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is [options](guide/en/#options), the last one is always [buildEnd](guide/en/#buildend). Additionally in watch mode, the [watchChange](guide/en/#watchchange) hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. +Build hooks are run during the build phase, which is triggered by `rollup.rollup(inputOptions)`. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is [`options`](guide/en/#options), the last one is always [`buildEnd`](guide/en/#buildend), unless there is a build error in which case [`closeBundle`](guide/en/#closebundle) will be called after that. + +Additionally, in watch mode the [`watchChange`](guide/en/#watchchange) hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the [`closeWatcher`](guide/en/#closewatcher) hook will be triggered. See [Output Generation Hooks](guide/en/#output-generation-hooks) for hooks that run during the output generation phase to modify the generated output. @@ -92,6 +94,13 @@ Next Hook: [`resolveId`](guide/en/#resolveid) to resolve each entry point in par Called on each `rollup.rollup` build. This is the recommended hook to use when you need access to the options passed to `rollup.rollup()` as it takes the transformations by all [`options`](guide/en/#options) hooks into account and also contains the right default values for unset options. +#### `closeWatcher` +Type: `() => void`
+Kind: `sync, sequential`
+Previous/Next Hook: This hook can be triggered at any time both during the build and the output generation phases. If that is the case, the current build will still proceed but no new [`watchChange`](guide/en/#watchchange) events will be triggered ever. + +Notifies a plugin when watcher process closes and all open resources should be closed too. This hook cannot be used by output plugins. + #### `load` Type: `(id: string) => string | null | {code: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}`
Kind: `async, first`
@@ -145,12 +154,12 @@ In case a dynamic import is not passed a string as argument, this hook gets acce - If a string is returned, this string is *not* interpreted as a module id but is instead used as a replacement for the import argument. It is the responsibility of the plugin to make sure the generated code is valid. - To resolve such an import to an existing module, you can still return an object `{id, external}`. -Note that the return value of this hook will not be passed to `resolveId` afterwards; if you need access to the static resolution algorithm, you can use [`this.resolve(source, importer)`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-custom-plugin-string-any--null) on the plugin context. +Note that the return value of this hook will not be passed to `resolveId` afterwards; if you need access to the static resolution algorithm, you can use [`this.resolve(source, importer)`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean--absolute-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-meta-plugin-string-any--null) on the plugin context. #### `resolveId` -Type: `(source: string, importer: string | undefined, options: {custom?: {[plugin: string]: any}) => string | false | null | {id: string, external?: boolean, moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}`
+Type: `(source: string, importer: string | undefined, options: {custom?: {[plugin: string]: any}) => string | false | null | {id: string, external?: boolean | "relative" | "absolute", moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}`
Kind: `async, first`
-Previous Hook: [`buildStart`](guide/en/#buildstart) if we are resolving an entry point, [`moduleParsed`](guide/en/#moduleparsed) if we are resolving an import, or as fallback for [`resolveDynamicImport`](guide/en/#resolvedynamicimport). Additionally this hook can be triggered during the build phase from plugin hooks by calling [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string) to emit an entry point or at any time by calling [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-custom-plugin-string-any--null) to manually resolve an id.
+Previous Hook: [`buildStart`](guide/en/#buildstart) if we are resolving an entry point, [`moduleParsed`](guide/en/#moduleparsed) if we are resolving an import, or as fallback for [`resolveDynamicImport`](guide/en/#resolvedynamicimport). Additionally this hook can be triggered during the build phase from plugin hooks by calling [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string) to emit an entry point or at any time by calling [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean--absolute-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-meta-plugin-string-any--null) to manually resolve an id.
Next Hook: [`load`](guide/en/#load) if the resolved id that has not yet been loaded, otherwise [`buildEnd`](guide/en/#buildend). Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Here `source` is the importee exactly as it is written in the import statement, i.e. for @@ -159,9 +168,9 @@ Defines a custom resolver. A resolver can be useful for e.g. locating third-part import { foo } from '../bar.js'; ``` -the source will be `"../bar.js""`. +the source will be `"../bar.js""`. -The `importer` is the fully resolved id of the importing module. When resolving entry points, importer will be `undefined`. You can use this for instance as a mechanism to define custom proxy modules for entry points. +The `importer` is the fully resolved id of the importing module. When resolving entry points, importer will be `undefined`. You can use this for instance as a mechanism to define custom proxy modules for entry points. The following plugin will only expose the default export from entry points while still keeping named exports available for internal usage: @@ -199,7 +208,7 @@ resolveId(source) { } ``` -Relative ids, i.e. starting with `./` or `../`, will **not** be renormalized when returning an object. If you want this behaviour, return an absolute file system location as `id` instead. +If `external` is `true`, then absolute ids will be converted to relative ids based on the user's choice for the [`makeAbsoluteExternalsRelative`](guide/en/#makeabsoluteexternalsrelative) option. This choice can be overridden by passing either `external: "relative"` to always convert an absolute id to a relative id or `external: "absolute"` to keep it as an absolute id. When returning an object, relative external ids, i.e. ids starting with `./` or `../`, will *not* be internally converted to an absolute id and converted back to a relative id in the output, but are instead included in the output unchanged. If you want relative ids to be renormalised and deduplicated instead, return an absolute file system location as `id` and choose `external: "relative"`. If `false` is returned for `moduleSideEffects` in the first hook that resolves a module id and no other module imports anything from this module, then this module will not be included even if the module would have side-effects. If `true` is returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable). If `"no-treeshake"` is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If `null` is returned or the flag is omitted, then `moduleSideEffects` will be determined by the `treeshake.moduleSideEffects` option or default to `true`. The `load` and `transform` hooks can override this. @@ -207,7 +216,7 @@ See [synthetic named exports](guide/en/#synthetic-named-exports) for the effect See [custom module meta-data](guide/en/#custom-module-meta-data) for how to use the `meta` option. If `null` is returned or the option is omitted, then `meta` will default to an empty object. The `load` and `transform` hooks can add or replace properties of this object. -When triggering this hook from a plugin via [`this.resolve(source, importer, options)`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-custom-plugin-string-any--null), it is possible to pass a custom options object to this hook. While this object will be passed unmodified, plugins should follow the convention of adding a `custom` property with an object where the keys correspond to the names of the plugins that the options are intended for. For details see [custom resolver options](guide/en/#custom-resolver-options). +When triggering this hook from a plugin via [`this.resolve(source, importer, options)`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean--absolute-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-meta-plugin-string-any--null), it is possible to pass a custom options object to this hook. While this object will be passed unmodified, plugins should follow the convention of adding a `custom` property with an object where the keys correspond to the names of the plugins that the options are intended for. For details see [custom resolver options](guide/en/#custom-resolver-options). #### `transform` Type: `(code: string, id: string) => string | null | {code?: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}`
@@ -221,11 +230,11 @@ Note that in watch mode, the result of this hook is cached when rebuilding and t You can also use the object form of the return value to configure additional properties of the module. Note that it's possible to return only properties and no code transformations. -If `false` is returned for `moduleSideEffects` and no other module imports anything from this module, then this module will not be included even if the module would have side-effects. +If `false` is returned for `moduleSideEffects` and no other module imports anything from this module, then this module will not be included even if the module would have side-effects. -If `true` is returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable). +If `true` is returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable). -If `"no-treeshake"` is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. +If `"no-treeshake"` is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If `null` is returned or the flag is omitted, then `moduleSideEffects` will be determined by the `load` hook that loaded this module, the first `resolveId` hook that resolved this module, the `treeshake.moduleSideEffects` option, or eventually default to `true`. @@ -236,17 +245,19 @@ See [custom module meta-data](guide/en/#custom-module-meta-data) for how to use You can use [`this.getModuleInfo`](guide/en/#thisgetmoduleinfomoduleid-string--moduleinfo--null) to find out the previous values of `moduleSideEffects`, `syntheticNamedExports` and `meta` inside this hook. #### `watchChange` -Type: `(id: string) => void`
+Type: `watchChange: (id: string, change: {event: 'create' | 'update' | 'delete'}) => void`
Kind: `sync, sequential`
Previous/Next Hook: This hook can be triggered at any time both during the build and the output generation phases. If that is the case, the current build will still proceed but a new build will be scheduled to start once the current build has completed, starting again with [`options`](guide/en/#options). -Notifies a plugin whenever rollup has detected a change to a monitored file in `--watch` mode. This hook cannot be used by output plugins. +Notifies a plugin whenever rollup has detected a change to a monitored file in `--watch` mode. This hook cannot be used by output plugins. Second argument contains additional details of change event. ### Output Generation Hooks Output generation hooks can provide information about a generated bundle and modify a build once complete. They work the same way and have the same types as [Build Hooks](guide/en/#build-hooks) but are called separately for each call to `bundle.generate(outputOptions)` or `bundle.write(outputOptions)`. Plugins that only use output generation hooks can also be passed in via the output options and therefore run only for certain outputs. -The first hook of the output generation phase is [outputOptions](guide/en/#outputoptions), the last one is either [generateBundle](guide/en/#generatebundle) if the output was successfully generated via `bundle.generate(...)`, [writeBundle](guide/en/#writebundle) if the output was successfully generated via `bundle.write(...)`, or [renderError](guide/en/#rendererror) if an error occurred at any time during the output generation. +The first hook of the output generation phase is [`outputOptions`](guide/en/#outputoptions), the last one is either [`generateBundle`](guide/en/#generatebundle) if the output was successfully generated via `bundle.generate(...)`, [`writeBundle`](guide/en/#writebundle) if the output was successfully generated via `bundle.write(...)`, or [`renderError`](guide/en/#rendererror) if an error occurred at any time during the output generation. + +Additionally, [`closeBundle`](guide/en/#closebundle) can be called as the very last hook, but it is the responsibility of the User to manually call [`bundle.close()`](guide/en/#rolluprollup) to trigger this. The CLI will always make sure this is the case. #### `augmentChunkHash` Type: `(chunkInfo: ChunkInfo) => string`
@@ -275,6 +286,15 @@ Next Hook: [`renderDynamicImport`](guide/en/#renderdynamicimport) for each dynam Cf. [`output.banner/output.footer`](guide/en/#outputbanneroutputfooter). +#### `closeBundle` +Type: `closeBundle: () => Promise | void`
+Kind: `async, parallel`
+Previous Hook: [`buildEnd`](guide/en/#buildend) if there was a build error, otherwise when [`bundle.close()`](guide/en/#rolluprollup) is called, in which case this would be the last hook to be triggered. + +Can be used to clean up any external service that may be running. Rollup's CLI will make sure this hook is called after each run, but it is the responsibility of users of the JavaScript API to manually call `bundle.close()` once they are done generating bundles. For that reason, any plugin relying on this feature should carefully mention this in its documentation. + +If a plugin wants to retain resources across builds in watch mode, they can check for [`this.meta.watchMode`](guide/en/#thismeta-rollupversion-string-watchmode-boolean) in this hook and perform the necessary cleanup for watch mode in [`closeWatcher`](guide/en/#closewatcher). + #### `footer` Type: `string | (() => string)`
Kind: `async, parallel`
@@ -319,7 +339,8 @@ Called at the end of `bundle.generate()` or immediately before the files are wri renderedExports: string[], removedExports: string[], renderedLength: number, - originalLength: number + originalLength: number, + code: string | null }, }, name: string, @@ -605,7 +626,7 @@ If there are no dynamic imports, this will create exactly three chunks where the Note that even though any module id can be used in `implicitlyLoadedAfterOneOf`, Rollup will throw an error if such an id cannot be uniquely associated with a chunk, e.g. because the `id` cannot be reached implicitly or explicitly from the existing static entry points, or because the file is completely tree-shaken. Using only entry points, either defined by the user or of previously emitted chunks, will always work, though. -If the `type` is *`asset`*, then this emits an arbitrary new file with the given `source` as content. It is possible to defer setting the `source` via [`this.setAssetSource(assetReferenceId, source)`](guide/en/#thissetassetsourceassetreferenceid-string-source-string--uint8array--void) to a later time to be able to reference a file during the build phase while setting the source separately for each output during the generate phase. Assets with a specified `fileName` will always generate separate files while other emitted assets may be deduplicated with existing assets if they have the same source even if the `name` does not match. If such an asset is not deduplicated, the [`output.assetFileNames`](guide/en/#outputassetfilenames) name pattern will be used. +If the `type` is *`asset`*, then this emits an arbitrary new file with the given `source` as content. It is possible to defer setting the `source` via [`this.setAssetSource(referenceId, source)`](guide/en/#thissetassetsourcereferenceid-string-source-string--uint8array--void) to a later time to be able to reference a file during the build phase while setting the source separately for each output during the generate phase. Assets with a specified `fileName` will always generate separate files while other emitted assets may be deduplicated with existing assets if they have the same source even if the `name` does not match. If such an asset is not deduplicated, the [`output.assetFileNames`](guide/en/#outputassetfilenames) name pattern will be used. #### `this.error(error: string | Error, position?: number | { column: number; line: number }) => never` @@ -647,6 +668,8 @@ Returns additional information about the module in question in the form implicitlyLoadedAfterOneOf: string[], // implicit relationships, declared via this.emitChunk implicitlyLoadedBefore: string[], // implicit relationships, declared via this.emitChunk hasModuleSideEffects: boolean | "no-treeshake" // are imports of this module included if nothing is imported from it + meta: {[plugin: string]: any} // custom module meta-data + syntheticNamedExports: boolean | string // final value of synthetic named exports } ``` @@ -655,6 +678,10 @@ During the build, this object represents currently available information about t Returns `null` if the module id cannot be found. +#### `this.getWatchFiles() => string[]` + +Get ids of the files which has been watched previously. Include both files added by plugins with `this.addWatchFile` and files added implicitly by rollup during the build. + #### `this.meta: {rollupVersion: string, watchMode: boolean}` An object containing potentially useful Rollup metadata: @@ -668,14 +695,14 @@ An object containing potentially useful Rollup metadata: Use Rollup's internal acorn instance to parse code to an AST. -#### `this.resolve(source: string, importer?: string, options?: {skipSelf?: boolean, custom?: {[plugin: string]: any}}) => Promise<{id: string, external: boolean, moduleSideEffects: boolean | 'no-treeshake', syntheticNamedExports: boolean | string, meta: {[plugin: string]: any}} | null>` -Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses, and determine if an import should be external. If `null` is returned, the import could not be resolved by Rollup or any plugin but was not explicitly marked as external by the user. +#### `this.resolve(source: string, importer?: string, options?: {skipSelf?: boolean, custom?: {[plugin: string]: any}}) => Promise<{id: string, external: boolean | "absolute", moduleSideEffects: boolean | 'no-treeshake', syntheticNamedExports: boolean | string, meta: {[plugin: string]: any}} | null>` +Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses, and determine if an import should be external. If `null` is returned, the import could not be resolved by Rollup or any plugin but was not explicitly marked as external by the user. If an absolute external id is returned that should remain absolute in the output either via the [`makeAbsoluteExternalsRelative`](guide/en/#makeabsoluteexternalsrelative) option or by explicit plugin choice in the [`resolveId`](guide/en/#resolveid) hook, `external` will be `"absolute"` instead of `true`. -If you pass `skipSelf: true`, then the `resolveId` hook of the plugin from which `this.resolve` is called will be skipped when resolving. +If you pass `skipSelf: true`, then the `resolveId` hook of the plugin from which `this.resolve` is called will be skipped when resolving. When other plugins themselves also call `this.resolve` in their `resolveId` hooks with the *exact same `source` and `importer`* while handling the original `this.resolve` call, then the `resolveId` hook of the original plugin will be skipped for those calls as well. The rationale here is that the plugin already stated that it "does not know" how to resolve this particular combination of `source` and `importer` at this point in time. If you do not want this behaviour, do not use `skipSelf` but implement your own infinite loop prevention mechanism if necessary. You can also pass an object of plugin-specific options via the `custom` option, see [custom resolver options](guide/en/#custom-resolver-options) for details. -#### `this.setAssetSource(assetReferenceId: string, source: string | Uint8Array) => void` +#### `this.setAssetSource(referenceId: string, source: string | Uint8Array) => void` Set the deferred source of an asset. Note that you can also pass a Node `Buffer` as `source` as it is a sub-class of `Uint8Array`. @@ -699,23 +726,23 @@ The `position` argument is a character index where the warning was raised. If pr ☢️ These context utility functions have been deprecated and may be removed in a future Rollup version. -- `this.emitAsset(assetName: string, source: string) => string` - _**Use [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string)**_ - Emits a custom file that is included in the build output, returning an `assetReferenceId` that can be used to reference the emitted file. You can defer setting the source if you provide it later via [`this.setAssetSource(assetReferenceId, source)`](guide/en/#thissetassetsourceassetreferenceid-string-source-string--uint8array--void). A string or `Uint8Array`/`Buffer` source must be set for each asset through either method or an error will be thrown on generate completion. +- `this.emitAsset(assetName: string, source: string) => string` - _**Use [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string)**_ - Emits a custom file that is included in the build output, returning a `referenceId` that can be used to reference the emitted file. You can defer setting the source if you provide it later via [`this.setAssetSource(referenceId, source)`](guide/en/#thissetassetsourcereferenceid-string-source-string--uint8array--void). A string or `Uint8Array`/`Buffer` source must be set for each asset through either method or an error will be thrown on generate completion. - Emitted assets will follow the [`output.assetFileNames`](guide/en/#outputassetfilenames) naming scheme. You can reference the URL of the file in any code returned by a [`load`](guide/en/#load) or [`transform`](guide/en/#transform) plugin hook via `import.meta.ROLLUP_ASSET_URL_assetReferenceId`. + Emitted assets will follow the [`output.assetFileNames`](guide/en/#outputassetfilenames) naming scheme. You can reference the URL of the file in any code returned by a [`load`](guide/en/#load) or [`transform`](guide/en/#transform) plugin hook via `import.meta.ROLLUP_ASSET_URL_referenceId`. - The generated code that replaces `import.meta.ROLLUP_ASSET_URL_assetReferenceId` can be customized via the [`resolveFileUrl`](guide/en/#resolvefileurl) plugin hook. Once the asset has been finalized during `generate`, you can also use [`this.getFileName(assetReferenceId)`](guide/en/#thisgetfilenamereferenceid-string--string) to determine the file name. + The generated code that replaces `import.meta.ROLLUP_ASSET_URL_referenceId` can be customized via the [`resolveFileUrl`](guide/en/#resolvefileurl) plugin hook. Once the asset has been finalized during `generate`, you can also use [`this.getFileName(referenceId)`](guide/en/#thisgetfilenamereferenceid-string--string) to determine the file name. -- `this.emitChunk(moduleId: string, options?: {name?: string}) => string` - _**Use [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string)**_ - Emits a new chunk with the given module as entry point. This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split. It returns a `chunkReferenceId` that can be used to later access the generated file name of the chunk. +- `this.emitChunk(moduleId: string, options?: {name?: string}) => string` - _**Use [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string)**_ - Emits a new chunk with the given module as entry point. This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split. It returns a `referenceId` that can be used to later access the generated file name of the chunk. - Emitted chunks will follow the [`output.chunkFileNames`](guide/en/#outputchunkfilenames), [`output.entryFileNames`](guide/en/#outputentryfilenames) naming scheme. If a `name` is provided, this will be used for the `[name]` file name placeholder, otherwise the name will be derived from the file name. If a `name` is provided, this name must not conflict with any other entry point names unless the entry points reference the same entry module. You can reference the URL of the emitted chunk in any code returned by a [`load`](guide/en/#load) or [`transform`](guide/en/#transform) plugin hook via `import.meta.ROLLUP_CHUNK_URL_chunkReferenceId`. + Emitted chunks will follow the [`output.chunkFileNames`](guide/en/#outputchunkfilenames), [`output.entryFileNames`](guide/en/#outputentryfilenames) naming scheme. If a `name` is provided, this will be used for the `[name]` file name placeholder, otherwise the name will be derived from the file name. If a `name` is provided, this name must not conflict with any other entry point names unless the entry points reference the same entry module. You can reference the URL of the emitted chunk in any code returned by a [`load`](guide/en/#load) or [`transform`](guide/en/#transform) plugin hook via `import.meta.ROLLUP_CHUNK_URL_referenceId`. - The generated code that replaces `import.meta.ROLLUP_CHUNK_URL_chunkReferenceId` can be customized via the [`resolveFileUrl`](guide/en/#resolvefileurl) plugin hook. Once the chunk has been rendered during `generate`, you can also use [`this.getFileName(chunkReferenceId)`](guide/en/#thisgetfilenamereferenceid-string--string) to determine the file name. + The generated code that replaces `import.meta.ROLLUP_CHUNK_URL_referenceId` can be customized via the [`resolveFileUrl`](guide/en/#resolvefileurl) plugin hook. Once the chunk has been rendered during `generate`, you can also use [`this.getFileName(referenceId)`](guide/en/#thisgetfilenamereferenceid-string--string) to determine the file name. -- `this.getAssetFileName(assetReferenceId: string) => string` - _**Use [`this.getFileName`](guide/en/#thisgetfilenamereferenceid-string--string)**_ - Get the file name of an asset, according to the `assetFileNames` output option pattern. The file name will be relative to `outputOptions.dir`. +- `this.getAssetFileName(referenceId: string) => string` - _**Use [`this.getFileName`](guide/en/#thisgetfilenamereferenceid-string--string)**_ - Get the file name of an asset, according to the `assetFileNames` output option pattern. The file name will be relative to `outputOptions.dir`. -- `this.getChunkFileName(chunkReferenceId: string) => string` - _**Use [`this.getFileName`](guide/en/#thisgetfilenamereferenceid-string--string)**_ - Get the file name of an emitted chunk. The file name will be relative to `outputOptions.dir`. +- `this.getChunkFileName(referenceId: string) => string` - _**Use [`this.getFileName`](guide/en/#thisgetfilenamereferenceid-string--string)**_ - Get the file name of an emitted chunk. The file name will be relative to `outputOptions.dir`. -- `this.isExternal(id: string, importer: string | undefined, isResolved: boolean) => boolean` - _**Use [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-custom-plugin-string-any--null)**_ - Determine if a given module ID is external when imported by `importer`. When `isResolved` is false, Rollup will try to resolve the id before testing if it is external. +- `this.isExternal(id: string, importer: string | undefined, isResolved: boolean) => boolean` - _**Use [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean--absolute-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-meta-plugin-string-any--null)**_ - Determine if a given module ID is external when imported by `importer`. When `isResolved` is false, Rollup will try to resolve the id before testing if it is external. - `this.moduleIds: IterableIterator` - _**Use [`this.getModuleIds`](guide/en/#thisgetmoduleids--iterableiteratorstring)**_ - An `Iterator` that gives access to all module ids in the current graph. It can be iterated via @@ -726,7 +753,7 @@ The `position` argument is a character index where the warning was raised. If pr or converted into an Array via `Array.from(this.moduleIds)`. -- `this.resolveId(source: string, importer?: string) => Promise` - _**Use [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-custom-plugin-string-any--null)**_ - Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses. Returns `null` if an id cannot be resolved. +- `this.resolveId(source: string, importer?: string) => Promise` - _**Use [`this.resolve`](guide/en/#thisresolvesource-string-importer-string-options-skipself-boolean-custom-plugin-string-any--promiseid-string-external-boolean--absolute-modulesideeffects-boolean--no-treeshake-syntheticnamedexports-boolean--string-meta-plugin-string-any--null)**_ - Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses. Returns `null` if an id cannot be resolved. ### File URLs @@ -882,7 +909,7 @@ return { ``` If you create a plugin that you think would be useful to others, please publish -it to NPM and add submit it to https://github.com/rollup/awesome! +it to NPM and add submit it to [github.com/rollup/awesome](https://github.com/rollup/awesome)! ### Synthetic named exports It is possible to designate a fallback export for missing exports by setting the `syntheticNamedExports` option for a module in the [`resolveId`](guide/en/#resolveid), [`load`](guide/en/#load) or [`transform`](guide/en/#transform) hook. If a string value is used for `syntheticNamedExports`, this module will fallback the resolution of any missing named exports to properties of the named export of the given name: diff --git a/docs/08-troubleshooting.md b/docs/08-troubleshooting.md index bd98e7b8147..74760ed0a46 100644 --- a/docs/08-troubleshooting.md +++ b/docs/08-troubleshooting.md @@ -2,7 +2,7 @@ title: Troubleshooting --- -If you get stuck, please try discussing the issue on [the Rollup Gitter](https://gitter.im/rollup/rollup) or posting a question to https://stackoverflow.com/questions/tagged/rollupjs. If you've found a bug, or Rollup can't meet your needs, please try [raising an issue](https://github.com/rollup/rollup/issues). Lastly, you may try contacting [@RollupJS](https://twitter.com/RollupJS) on Twitter. +If you get stuck, please try discussing the issue on the [Rollup Discord](https://is.gd/rollup_chat) or posting a question to [Stackoverflow](https://stackoverflow.com/questions/tagged/rollupjs). If you've found a bug, or Rollup can't meet your needs, please try [raising an issue](https://github.com/rollup/rollup/issues). Lastly, you may try contacting [@RollupJS](https://twitter.com/RollupJS) on Twitter. ### Avoiding `eval` @@ -64,9 +64,9 @@ There are occasional valid reasons for `this` to mean something else. If you're ### Warning: "Sourcemap is likely to be incorrect" -You'll see this warning if you generate a sourcemap with your bundle (`sourceMap: true` or `sourceMap: 'inline'`) but you're using one or more plugins that transformed code without generating a sourcemap for the transformation. +You'll see this warning if you generate a sourcemap with your bundle (`sourcemap: true` or `sourcemap: 'inline'`) but you're using one or more plugins that transformed code without generating a sourcemap for the transformation. -Usually, a plugin will only omit the sourcemap if it (the plugin, not the bundle) was configured with `sourceMap: false` – so all you need to do is change that. If the plugin doesn't generate a sourcemap, consider raising an issue with the plugin author. +Usually, a plugin will only omit the sourcemap if it (the plugin, not the bundle) was configured with `sourcemap: false` – so all you need to do is change that. If the plugin doesn't generate a sourcemap, consider raising an issue with the plugin author. ### Warning: "Treating [module] as external dependency" @@ -108,4 +108,4 @@ export default { } } }; -``` \ No newline at end of file +``` diff --git a/docs/999-big-list-of-options.md b/docs/999-big-list-of-options.md index 153aa16577b..42fa0f9cf06 100755 --- a/docs/999-big-list-of-options.md +++ b/docs/999-big-list-of-options.md @@ -35,7 +35,7 @@ When given as a command line argument, it should be a comma-separated list of ID rollup -i src/main.js ... -e foo,bar,baz ``` -When providing a function, it is actually called with three parameters `(id, parent, isResolved)` that can give you more fine-grained control: +When providing a function, it is called with three parameters `(id, parent, isResolved)` that can give you more fine-grained control: * `id` is the id of the module in question * `parent` is the id of the module doing the import @@ -135,7 +135,7 @@ Specifies the format of the generated bundle. One of the following: * `amd` – Asynchronous Module Definition, used with module loaders like RequireJS * `cjs` – CommonJS, suitable for Node and other bundlers (alias: `commonjs`) * `es` – Keep the bundle as an ES module file, suitable for other bundlers and inclusion as a `