{"id":13484095,"url":"https://github.com/cyrilwanner/next-compose-plugins","last_synced_at":"2025-05-15T09:06:52.940Z","repository":{"id":30392003,"uuid":"124764243","full_name":"cyrilwanner/next-compose-plugins","owner":"cyrilwanner","description":"💡next-compose-plugins provides a cleaner API for enabling and configuring plugins for next.js","archived":false,"fork":false,"pushed_at":"2022-12-07T17:56:15.000Z","size":1058,"stargazers_count":739,"open_issues_count":32,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-15T09:06:52.540Z","etag":null,"topics":["compose","nextjs","plugin","react"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cyrilwanner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-11T14:22:35.000Z","updated_at":"2025-04-17T07:16:18.000Z","dependencies_parsed_at":"2023-01-14T17:00:38.988Z","dependency_job_id":null,"html_url":"https://github.com/cyrilwanner/next-compose-plugins","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyrilwanner%2Fnext-compose-plugins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyrilwanner%2Fnext-compose-plugins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyrilwanner%2Fnext-compose-plugins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyrilwanner%2Fnext-compose-plugins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cyrilwanner","download_url":"https://codeload.github.com/cyrilwanner/next-compose-plugins/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310515,"owners_count":22049469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compose","nextjs","plugin","react"],"created_at":"2024-07-31T17:01:19.374Z","updated_at":"2025-05-15T09:06:52.917Z","avatar_url":"https://github.com/cyrilwanner.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# :bulb: next-compose-plugins [![npm version](https://badgen.net/npm/v/next-compose-plugins)](https://www.npmjs.com/package/next-compose-plugins) [![license](https://badgen.net/github/license/cyrilwanner/next-compose-plugins)](https://github.com/cyrilwanner/next-compose-plugins/blob/master/LICENSE) [![downloads](https://badgen.net/npm/dt/next-compose-plugins)](https://www.npmjs.com/package/next-compose-plugins)\n\nProvides a cleaner API for enabling and configuring plugins for [next.js](https://github.com/zeit/next.js) because the default way next.js suggests to enable and configure plugins can get unclear and confusing when you have many plugins.\n\nIt is often unclear which plugins are enabled or which configuration belongs to which plugin because they are nested and share one configuration object.\nThis can also lead to orphaned configuration values when updating or removing plugins.\n\nWhile `next-compose-plugins` tries to eliminate this case by providing an alternative API for enabling and configuring plugins where each plugin has their own configuration object, it also adds more features like phase specific plugins and configuration.\n\n## Table of contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [`withPlugins`](#usage)\n  - [Optional plugins](#optional-plugins)\n  - [Extend another config file](#extend-another-config-file)\n- [Plugin developers](#plugin-developers)\n- [Examples](#examples)\n- [See also](#see-also)\n- [License](#license)\n\n## Installation\n\n```\nnpm install --save next-compose-plugins\n```\n\n---\n\n\u003ca href=\"https://www.creative-tim.com/product/nextjs-material-dashboard-pro/?ref=next-compose-plugins\"\u003e\u003cimg src=\"https://cyrilwanner.github.io/packages/next-compose-plugins/assets/material-dashboard.png?v=2\" alt=\"NextJS Material Dashboard\" align=\"right\" width=\"300px\"\u003e\u003c/a\u003e\n\u003cbr /\u003e\n\nBuilding a **Dashboard** or **Admin UI**? Or do you want to see a **usage example** of `next-compose-plugins` in a real world project? Check out the [NextJS Material Dashboard](https://www.creative-tim.com/product/nextjs-material-dashboard-pro/?ref=next-compose-plugins) by our partners [Creative Tim](https://www.creative-tim.com/?ref=next-compose-plugins) to get you started.\n\n\u003cbr /\u003e\u003cbr /\u003e\u003cbr /\u003e\n\n## Usage\n\n```javascript\n// next.config.js\nconst withPlugins = require('next-compose-plugins');\n\nmodule.exports = withPlugins([...plugins], nextConfiguration);\n```\n\n### `plugins`\n\n\u003e See the [examples](#examples) for more use-cases.\n\nIt is an array containing all plugins and their configuration.\nIf a plugin does not need additional configuration, you can simply add the imported plugin.\nIf it does need configuration or you only want to run it in a specific phase, you can specify an array:\n\n#### `[plugin: function, configuration?: object, phases?: array]`\n\n##### `plugin: function`\n\nImported plugin.\nSee the [optional plugins](#optional-plugins) section if you only want to require a plugin when it is really used.\n\n```javascript\nconst withPlugins = require('next-compose-plugins');\nconst sass = require('@zeit/next-sass');\n\nmodule.exports = withPlugins([\n  [sass],\n]);\n```\n\n##### `configuration?: object`\n\nConfiguration for the plugin.\n\nYou can also overwrite specific configuration keys for a phase:\n\n```javascript\nconst withPlugins = require('next-compose-plugins');\nconst { PHASE_PRODUCTION_BUILD } = require('next/constants');\nconst sass = require('@zeit/next-sass');\n\nmodule.exports = withPlugins([\n  [sass, {\n    cssModules: true,\n    cssLoaderOptions: {\n      localIdentName: '[path]___[local]___[hash:base64:5]',\n    },\n    [PHASE_PRODUCTION_BUILD]: {\n      cssLoaderOptions: {\n        localIdentName: '[hash:base64:8]',\n      },\n    },\n  }],\n]);\n```\n\nThis will overwrite the `cssLoaderOptions` with the new `localIdentName` specified, but **only** during production build.\nYou can also combine multiple phases (`[PHASE_PRODUCTION_BUILD + PHASE_PRODUCTION_SERVER]: {}`) or exclude a phase (`['!' + PHASE_PRODUCTION_BUILD]: {}` which will overwrite the config in all phases except `PRODUCTION_BUILD`).\nYou can use all phases [next.js provides](https://github.com/zeit/next.js/blob/canary/packages/next/next-server/lib/constants.ts#L1-L4).\n\n##### `phases?: array`\n\nIf the plugin should only be applied in specific phases, you can specify them here.\nYou can use all phases [next.js provides](https://github.com/zeit/next.js/blob/canary/packages/next/next-server/lib/constants.ts#L1-L4).\n\n```javascript\nconst withPlugins = require('next-compose-plugins');\nconst { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } = require('next/constants');\nconst sass = require('@zeit/next-sass');\n\nmodule.exports = withPlugins([\n  [sass, {\n    cssModules: true,\n    cssLoaderOptions: {\n      localIdentName: '[path]___[local]___[hash:base64:5]',\n    },\n  }, [PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD]],\n]);\n```\n\nYou can also negate the phases with a leading `!`:\n\n```javascript\nconst withPlugins = require('next-compose-plugins');\nconst { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } = require('next/constants');\nconst sass = require('@zeit/next-sass');\n\nmodule.exports = withPlugins([\n  [sass, {\n    cssModules: true,\n    cssLoaderOptions: {\n      localIdentName: '[path]___[local]___[hash:base64:5]',\n    },\n  }, ['!', PHASE_DEVELOPMENT_SERVER]],\n]);\n```\n\nThis will apply the plugin in all phases except `PHASE_DEVELOPMENT_SERVER`.\n\n### `nextConfiguration`\n\nAny direct [next.js configuration](https://github.com/zeit/next.js#custom-configuration) can go here, for example: `{distDir: 'dist'}`.\n\nYou can also customize the webpack configuration of next.js within this object.\n\n```javascript\nconst withPlugins = require('next-compose-plugins');\n\nconst nextConfig = {\n  distDir: 'build',\n  webpack: (config, options) =\u003e {\n\n    // modify the `config` here\n\n    return config;\n  },\n};\n\nmodule.exports = withPlugins([\n  // add plugins here..\n], nextConfig);\n```\n\nPhases are also supported within the `nextConfiguration` object and have the same syntax as in [plugin `configuration` objects](#configuration-object).\n```javascript\nconst { PHASE_DEVELOPMENT_SERVER } = require('next/constants');\nconst nextConfig = {\n  distDir: 'build',\n  ['!' + PHASE_DEVELOPMENT_SERVER]: {\n    assetPrefix: 'https://my.cdn.com',\n  },\n};\n```\n\n### Optional plugins\n\nIf a plugin should only get loaded when it is used, you can use the `optional` helper function.\nThis can especially be useful if the plugin is only in the `devDependencies` and so may not be available in all phases.\nIf you don't use the `optional` helper in this case, you would get an error.\n\n```javascript\nconst { withPlugins, optional } = require('next-compose-plugins');\nconst { PHASE_DEVELOPMENT_SERVER } = require('next/constants');\n\nmodule.exports = withPlugins([\n  [optional(() =\u003e require('@zeit/next-sass')), { /* optional configuration */ }, [PHASE_DEVELOPMENT_SERVER]],\n]);\n```\n\n### Extend another config file\n\nIt sometimes makes sense to split a `next.config.js` file into multiple files, for example when you have more than just one next.js project in one repository.\nYou can then define the base config in one file and add project specific plugins/settings in the config file or the project.\n\nTo easily archive this, you can use the `extend` helper in the `next.config.js` file of your project.\n\n```javascript\n// next.config.js\nconst { withPlugins, extend } = require('next-compose-plugins');\nconst baseConfig = require('./base.next.config.js');\n\nconst nextConfig = { /* ... */ };\n\nmodule.exports = extend(baseConfig).withPlugins([\n  [sass, {\n    cssModules: true,\n  }],\n], nextConfig);\n```\n\n```javascript\n// base.next.config.js\nconst withPlugins = require('next-compose-plugins');\n\nmodule.exports = withPlugins([\n  [typescript, {\n    typescriptLoaderOptions: {\n      transpileOnly: false,\n    },\n  }],\n]);\n```\n\n## Plugin developers\n\nThis plugin has a few extra functionality which you can use as a plugin developer.\nHowever, if you use them, you should mention somewhere in your readme or install instructions that it needs `next-compose-plugins` to have all features available and so it won't confuse your users if something is not working as described out-of-the-box because they don't use this compose plugin yet.\n\n### Phases\n\nYou can specify in which phases your plugin should get executed within the object you return:\n\n```javascript\nconst { PHASE_DEVELOPMENT_SERVER } = require('next/constants');\n\nmodule.exports = (nextConfig = {}) =\u003e {\n  return Object.assign({}, nextConfig, {\n    // define in which phases this plugin should get applied.\n    // you can also use multiple phases or negate them.\n    // however, users can still overwrite them in their configuration if they really want to.\n    phases: [PHASE_DEVELOPMENT_SERVER],\n\n    webpack(config, options) {\n      // do something here which only gets applied during development server phase\n\n      if (typeof nextConfig.webpack === 'function') {\n        return nextConfig.webpack(config, options);\n      }\n\n      return config;\n    },\n  };\n};\n```\n\nThese phases are handled as a default configuration and users can overwrite the phases in their `next.config.js` file if they want to.\nSee [phases configuration](#phases-array) for all available options.\n\n### Additional information\n\nWhen a plugin gets loaded with `next-compose-plugins`, some additional information on which you can depend is available.\nIt gets passed in as the second argument to your plugin function:\n\n```javascript\nmodule.exports = (nextConfig = {}, nextComposePlugins = {}) =\u003e {\n  console.log(nextComposePlugins);\n};\n```\n\nCurrently, it contains these values:\n\n```javascript\n{\n  // this is always true when next-compose-plugins is used\n  // so you can use this as a check when your plugin depends on it\n  nextComposePlugins: boolean,\n\n  // the current phase which gets applied\n  phase: string,\n}\n```\n\n## Examples\n\n### Real world example\n\nCheck out the [NextJS Material Dashboard](https://www.creative-tim.com/product/nextjs-material-dashboard-pro/?ref=next-compose-plugins) by our partners [Creative Tim](https://www.creative-tim.com/?ref=next-compose-plugins) to see how `next-compose-plugins` was used in a real world application.\n\n### Basic example\n\n```javascript\n// next.config.js\nconst withPlugins = require('next-compose-plugins');\nconst images = require('next-images');\nconst sass = require('@zeit/next-sass');\nconst typescript = require('@zeit/next-typescript');\n\n// next.js configuration\nconst nextConfig = {\n  useFileSystemPublicRoutes: false,\n  distDir: 'build',\n};\n\nmodule.exports = withPlugins([\n\n  // add a plugin with specific configuration\n  [sass, {\n    cssModules: true,\n    cssLoaderOptions: {\n      localIdentName: '[local]___[hash:base64:5]',\n    },\n  }],\n\n  // add a plugin without a configuration\n  images,\n\n  // another plugin with a configuration\n  [typescript, {\n    typescriptLoaderOptions: {\n      transpileOnly: false,\n    },\n  }],\n\n], nextConfig);\n```\n\n### Advanced example\n\n```javascript\n// next.config.js\nconst { withPlugins, optional } = require('next-compose-plugins');\nconst images = require('next-images');\nconst sass = require('@zeit/next-sass');\nconst typescript = require('@zeit/next-typescript');\n\nconst {\n  PHASE_PRODUCTION_BUILD,\n  PHASE_PRODUCTION_SERVER,\n  PHASE_DEVELOPMENT_SERVER,\n  PHASE_EXPORT,\n} = require('next/constants');\n\n// next.js configuration\nconst nextConfig = {\n  useFileSystemPublicRoutes: false,\n  distDir: 'build',\n};\n\nmodule.exports = withPlugins([\n\n  // add a plugin with specific configuration\n  [sass, {\n    cssModules: true,\n    cssLoaderOptions: {\n      localIdentName: '[local]___[hash:base64:5]',\n    },\n    [PHASE_PRODUCTION_BUILD + PHASE_EXPORT]: {\n      cssLoaderOptions: {\n        localIdentName: '[hash:base64:8]',\n      },\n    },\n  }],\n\n  // add a plugin without a configuration\n  images,\n\n  // another plugin with a configuration (applied in all phases except development server)\n  [typescript, {\n    typescriptLoaderOptions: {\n      transpileOnly: false,\n    },\n  }, ['!', PHASE_DEVELOPMENT_SERVER]],\n\n  // load and apply a plugin only during development server phase\n  [optional(() =\u003e require('@some-internal/dev-log')), [PHASE_DEVELOPMENT_SERVER]],\n\n], nextConfig);\n```\n\n### Comparison\n\nAs a comparison, it would look like this without this plugin where it is not really clear which configuration belongs to which plugin and what are all the enabled plugins. Many features mentioned above will also not be possible or requires you to have a lot more custom code in your config file.\n\n```javascript\n// next.config.js\nconst withSass = require('@zeit/next-sass');\nconst withTypescript = require('@zeit/next-typescript');\nconst withImages = require('next-images');\nconst withOffline = require('next-offline');\n\nmodule.exports = withSass(withOffline(withTypescript(withImages({\n    {\n        cssModules: true,\n        cssLoaderOptions: {\n            importLoaders: 1,\n            localIdentName: '[local]___[hash:base64:5]',\n        },\n        typescriptLoaderOptions: {\n            transpileOnly: false,\n        },\n        useFileSystemPublicRoutes: false,\n        distDir: 'build',\n        workerName: 'sw.js',\n        imageTypes: ['jpg', 'png'],\n    }\n}))));\n```\n\n## See also\n\nSee [vercel/next-plugins](https://github.com/vercel/next-plugins) for a list of official and community made plugins for [next.js](https://github.com/vercel/next.js).\n\n## License\n\n[MIT](https://github.com/cyrilwanner/next-compose-plugins/blob/master/LICENSE) © Cyril Wanner\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyrilwanner%2Fnext-compose-plugins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcyrilwanner%2Fnext-compose-plugins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyrilwanner%2Fnext-compose-plugins/lists"}