├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── babel.config.json
├── jest.config.js
├── lerna.json
├── package-lock.json
├── package.json
└── packages
├── create-react-pkg
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
│ ├── index.js
│ ├── pkgTemplate.js
│ └── utils.js
├── templates
│ ├── baseFiles
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── gitignore
│ │ └── playground
│ │ │ ├── index.html
│ │ │ └── index.js
│ ├── basic-storybook
│ │ ├── .storybook
│ │ │ ├── main.js
│ │ │ └── preview.js
│ │ ├── src
│ │ │ └── index.js
│ │ ├── stories
│ │ │ └── MyComponent.stories.jsx
│ │ └── test
│ │ │ └── index.test.js
│ ├── basic
│ │ ├── src
│ │ │ └── index.js
│ │ └── test
│ │ │ └── index.test.js
│ ├── typescript-storybook
│ │ ├── .storybook
│ │ │ ├── main.js
│ │ │ └── preview.js
│ │ ├── src
│ │ │ └── index.tsx
│ │ ├── stories
│ │ │ └── MyComponent.stories.tsx
│ │ ├── test
│ │ │ └── index.test.tsx
│ │ └── tsconfig.json
│ └── typescript
│ │ ├── src
│ │ └── index.tsx
│ │ ├── test
│ │ └── index.test.tsx
│ │ └── tsconfig.json
└── test
│ └── utils.test.js
└── react-pkg-scripts
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
├── config.js
├── eslint
│ └── eslintFormatter.js
├── index.js
├── jest
│ ├── babelTransform.js
│ └── cssTransform.js
├── paths.js
├── rollup
│ ├── rollupConfig.js
│ ├── rollupESLintPlugin.js
│ └── rollupGenerateHtml.js
├── scripts
│ ├── build.js
│ ├── preview.js
│ ├── test.js
│ └── watch.js
├── types
│ └── index.d.ts
└── utils.js
└── test
└── utils.test.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | packages/create-react-pkg/templates
3 | lib
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es2021": true,
4 | "node": true,
5 | "jest": true
6 | },
7 | "extends": "eslint:recommended",
8 | "parserOptions": {
9 | "ecmaVersion": "latest",
10 | "sourceType": "module"
11 | },
12 | "rules": {}
13 | }
14 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | name: Node.js CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | test:
11 | name: Test on Node ${{ matrix.node-version }} and ${{ matrix.os }}
12 | runs-on: ${{ matrix.os }}
13 |
14 | strategy:
15 | matrix:
16 | node-version: [14.x, 16.x]
17 | os: [ubuntu-latest]
18 | # os: [ubuntu-latest, windows-latest, macOS-latest]
19 |
20 | steps:
21 | - name: Checkout repo
22 | uses: actions/checkout@v2
23 |
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v2
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'npm'
29 |
30 | - name: Install deps
31 | run: npm ci
32 |
33 | - name: Install package deps
34 | run: lerna bootstrap
35 |
36 | - name: Lint
37 | run: npm run lint
38 |
39 | - name: Build
40 | run: npm run build
41 |
42 | - name: Test
43 | run: npm test
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-present Haseeb Anwar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Create React Package
2 |
3 | Create React packages with no build configuration.
4 |
5 | ## Quick Overview
6 |
7 | ```sh
8 | npx create-react-pkg my-package
9 | cd my-package
10 | npm start
11 | ```
12 |
13 | You don’t need to install or configure tools like Rollup, Babel, or ESLint. They are pre-configured and hidden so that you can focus on the code.
14 |
15 | ## Contents
16 |
17 | - [Why](#why)
18 | - [Getting Started](#getting-started)
19 | - [Choose Package Manager](#choose-package-manager)
20 | - [npm](#npm)
21 | - [yarn](#yarn)
22 | - [Options](#options)
23 | - [Available Scripts](#available-scripts)
24 | - [`npm start` or `yarn start`](#npm-start-or-yarn-start)
25 | - [`npm test` or `yarn test`](#npm-test-or-yarn-test)
26 | - [`npm run build` or `yarn build`](#npm-run-build-or-yarn-build)
27 | - [`npm run preview` or `yarn preview`](#npm-run-preview-or-yarn-preview)
28 | - [Building your Package](#building-your-package)
29 | - [Install a Dependency](#install-a-dependency)
30 | - [Manage External Dependencies](#manage-external-dependencies)
31 | - [Preview](#preview)
32 | - [Build and Publish](#build-and-publish)
33 | - [Integrated Playground](#integrated-playground)
34 | - [Specify port for Server](#specify-port-for-server)
35 | - [Use CJS build with Playground](#use-cjs-build-with-playground)
36 | - [Philosophy](#philosophy)
37 | - [Customization](#customization)
38 | - [Config Intellisense](#config-intellisense)
39 | - [Config Options](#config-options)
40 | - [Rollup](#rollup)
41 | - [Conditional Rollup Config](#conditional-rollup-config)
42 | - [Example: Import images](#example-import-images)
43 | - [Babel](#babel)
44 | - [Example: Optimize Lodash](#example-optimize-lodash)
45 | - [ESLint](#eslint)
46 | - [Jest](#jest)
47 | - [CLI Options](#cli-options)
48 | - [Styling](#styling)
49 | - [Sass/Stylus/Less Files](#sassstylusless-files)
50 | - [Post-Processing CSS](#post-processing-css)
51 | - [Advanced Usage](#advanced-usage)
52 | - [Code Splitting](#code-splitting)
53 | - [Configure Supported Browsers](#configure-supported-browsers)
54 | - [Author](#author)
55 | - [License](#license)
56 |
57 | ## Why
58 |
59 | - Get started in seconds, easy to maintain, just one dependency
60 | - CJS, ESM, and UMD modules support
61 | - Pre-configured Rollup, Babel, Jest, and ESLint
62 | - Completely customizable
63 | - Integrated Playground
64 | - Tree-shaking
65 | - Code-splitting
66 | - Dev/Production builds
67 | - TypeScript support
68 | - Storybook support
69 | - Compile-time linting with ESLint
70 | - Out-of-the-box support for CSS, SASS, and JSON files
71 | - Pre-configured Browserslist, Sourcemaps, and Minification
72 | - VSCode friendly errors
73 |
74 | ## Getting Started
75 |
76 | ### Choose Package Manager
77 |
78 | **You’ll need to have Node 14.17.0 or a later version on your local development machine**. It is recommended to use the latest LTS version. You can use [nvm](https://github.com/creationix/nvm#installation) (macOS/Linux) or [nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows) to switch Node versions between different projects.
79 |
80 | To create a new package, you may choose one of the following methods:
81 |
82 | #### npm
83 |
84 | ```sh
85 | npx create-react-pkg my-package
86 | ```
87 |
88 | or
89 |
90 | ```sh
91 | npm create react-pkg my-package
92 | ```
93 |
94 | #### yarn
95 |
96 | ```sh
97 | yarn create react-pkg my-package
98 | ```
99 |
100 | ### Options
101 |
102 | `create-react-pkg` comes with the following options:
103 |
104 | - **--ts, --typescript**: Initialize a TypeScript project.
105 | - **--sb, --storybook**: Add storybook support.
106 |
107 | ```shell
108 | # npx
109 | npx create-react-pkg my-package --ts
110 |
111 | # npm 6.x
112 | npm create react-pkg my-package --ts
113 |
114 | # npm 7+, extra double dash is needed
115 | npm create react-pkg my-package -- --ts
116 |
117 | # yarn
118 | yarn create react-pkg my-package --ts
119 | ```
120 |
121 | ### Available Scripts
122 |
123 | Inside the newly created project, you can run some built-in commands:
124 |
125 | #### `npm start` or `yarn start`
126 |
127 | Runs the project in development mode, watches for file changes, and rebuilds on change. The build errors and lint warnings are printed in the console as you go.
128 |
129 |
130 |
131 |
132 |
133 | #### `npm test` or `yarn test`
134 |
135 | Runs your tests with Jest test runner.
136 |
137 | #### `npm run build` or `yarn build`
138 |
139 | Creates an optimized production build of your package in CommonJS, ES, and UMD module formats.
140 |
141 | #### `npm run preview` or `yarn preview`
142 |
143 | Opens the integrated playground app from `playground/index.js` in the browser for developing and previewing your library. The development server comes with live reload that makes development much easier.
144 |
145 | Read more in [Integrated Playground](#integrated-playground) section.
146 |
147 | ## Building your Package
148 |
149 | ### Install a Dependency
150 |
151 | The generated project includes `react` and `react-dom` along with the scripts used by Create React Package as development dependencies.
152 |
153 | You may install other dependencies, for example, Material UI:
154 |
155 | ```sh
156 | npm i -D @mui/material
157 | ```
158 |
159 | Since you are building a library, you probably need to install Material UI or other related frameworks as dev dependencies. It is the responsibility of the app consuming your library to have these dependencies installed.
160 |
161 | It is important that you define such dependencies as external dependencies.
162 |
163 | ### Manage External Dependencies
164 |
165 | External dependencies are those that should not be included in the bundled code of your library and should be installed by the consumer of the library.
166 |
167 | To specify external dependencies, add them to `peerDependencies` key in your package.json
168 |
169 | ```json
170 | "peerDependencies": {
171 | "react": ">=17",
172 | "react-dom": ">=17",
173 | "@mui/material": "^5.9.2"
174 | },
175 | ```
176 |
177 | Create React package already specifies `react` and `react-dom` as peer dependencies.
178 |
179 | ### Preview
180 |
181 | To preview and test your library before publishing, you can use:
182 |
183 | - [Integrated Playground](#integrated-playground)
184 | - [Storybook](https://storybook.js.org/)
185 | - [npm-link](https://docs.npmjs.com/cli/v8/commands/npm-link) with your React app
186 |
187 | Using Storybook with Create React Package is simple. Initialize a new project with Storybook using `--sb` or `--storybook` flag.
188 |
189 | ```sh
190 | npx create-react-pkg my-package --sb
191 | ```
192 |
193 | Or, add Storybook to your existing project by running:
194 |
195 | ```sh
196 | npx storybook init
197 | ```
198 |
199 | ### Build and Publish
200 |
201 | Create an optimized production build by running the `build` script. This will create a `dist` folder that may contain any or all of the folders based on your project setup and configuration:
202 |
203 | - cjs: Your library bundled in CommonJS format.
204 | - esm: Your library bundled in ECMAScript Modules format.
205 | - umd: Your library bundled in Universal Module Definition.
206 | - types: TypeScript declarations.
207 | - css: Minified CSS Bundle.
208 |
209 | > Note: If you use CJS as one of the module formats, it will create a file `dist/index.js` that loads CJS dev/prod builds based on the NodeJS environment.
210 |
211 | Create React Package adds the following NPM configuration to your package.json.
212 |
213 | ```json
214 | {
215 | "main": "dist/index.js (path to CJS build)",
216 | "module": "dist/esm/{your-package-name}.js (path to ES Module build)",
217 | "types": "dist/types/index.d.ts (path to TypeScript declarations)",
218 | "files": ["dist (files/folders that will be published to the NPM registry)"]
219 | }
220 | ```
221 |
222 | This build can now be published to NPM.
223 |
224 | ## Integrated Playground
225 |
226 | Integrated playground is a React app development server that makes it significantly easier to build and view your React library in browser.
227 |
228 | To get started with the playground, first run:
229 |
230 | ```shell
231 | npm start
232 | ```
233 |
234 | This builds your library to `/dist` and starts the project in watch mode so any edits you save inside `/src` causes a rebuild to `/dist`.
235 |
236 | Then run the playground inside another terminal:
237 |
238 | ```shell
239 | npm run preview
240 | ```
241 |
242 | The playground imports and live reloads your library from `/dist`, so if you see an out-of-date component, make sure the project is running in watch mode with either ESM or CJS build, or both. **No symlinking required**.
243 |
244 |
245 |
246 |
247 |
248 | > Tip: Use [`playground.rollupOptions`](#playgroundrollupoptions) config option for customizing the app bundle. For example, if you need to import images in your playground app.
249 |
250 | ### Specify port for Server
251 |
252 | By default, the server runs on port 10001, you can change it by creating a file `crp.config.js` at the root of package with the following.
253 |
254 | ```js
255 | const { defineConfig } = require('react-pkg-scripts');
256 |
257 | module.exports = defineConfig({
258 | playground: {
259 | server: {
260 | port: 3000, // define port of your choice
261 | },
262 | },
263 | });
264 | ```
265 |
266 | ### Use CJS build with Playground
267 |
268 | By default, the playground tries to use the ESM build of your library from `/dist`. But you can use the CJS build by removing the `module` property from package.json
269 |
270 | ```diff
271 | {
272 | "name": "foo",
273 | "main": "dist/index.js"
274 | - "module": "dist/esm/foo.js"
275 | }
276 | ```
277 |
278 | Or you can point the module entry to CJS entry point
279 |
280 | ```diff
281 | {
282 | "name": "foo",
283 | "main": "dist/index.js"
284 | - "module": "dist/esm/foo.js"
285 | + "module": "dist/index.js"
286 | }
287 | ```
288 |
289 | ## Philosophy
290 |
291 | Create React Package is divided into two packages:
292 |
293 | - `create-react-pkg` is a command line tool to set up a new React package.
294 | - `react-pkg-scripts` is a development dependency in the generated projects that encapsulates all the build tools.
295 |
296 | ## Customization
297 |
298 | Create React Package uses Rollup, Babel, Jest, and ESLint under the hood. These tools are pre-configured, and the default configuration is enough for most packages but you can customize them to your needs.
299 |
300 | > Customization can invalidate the default behavior of Create React Package. Please use with discretion.
301 |
302 | Create a file called `crp.config.js` at the root of your project like so:
303 |
304 | ```js
305 | const { defineConfig } = require('react-pkg-scripts');
306 |
307 | module.exports = defineConfig({
308 | // options
309 | });
310 | ```
311 |
312 | > Note: Create React Package does not support ES modules syntax in the config file, so use plain Node.js
313 |
314 | ### Config Intellisense
315 |
316 | Since Create React Package ships with TypeScript typings, you can leverage your IDE's IntelliSense with JSDoc type hints:
317 |
318 | ```js
319 | // crp.config.js
320 |
321 | /**
322 | * @type {import('react-pkg-scripts').UserConfig}
323 | */
324 | const config = {
325 | // options
326 | };
327 |
328 | module.exports = config;
329 | ```
330 |
331 | Alternatively, you can use the `defineConfig` helper which should provide IntelliSense without the need for JSDoc annotations:
332 |
333 | ```js
334 | // crp.config.js
335 |
336 | const { defineConfig } = require('react-pkg-scripts');
337 |
338 | module.exports = defineConfig({
339 | // options
340 | });
341 | ```
342 |
343 | ### Config Options
344 |
345 | You can provide the following options to customize the build.
346 |
347 | #### input
348 |
349 | - **Type**: `string`
350 | - **Default**: `src/index`
351 |
352 | Entry point
353 |
354 | #### outDir
355 |
356 | - **Type**: `string`
357 | - **Default**: `dist`
358 |
359 | Directory relative from root where build output will be placed. If the directory exists, it will be removed before the build.
360 |
361 | #### formats
362 |
363 | - **Type**: `string[]`
364 | - **Default**: `['cjs', 'esm']`
365 |
366 | Bundle formats. Available formats are `cjs`, `esm`, and `umd`
367 |
368 | #### name
369 |
370 | - **Type**: `string`
371 | - **Default**: `camel-cased version of your package name`
372 |
373 | Name to expose in the UMD build. Use this option when you are using `umd` as one of the build formats.
374 |
375 | #### disableESLint
376 |
377 | - **Type**: `boolean`
378 | - **Default**: `false`
379 |
380 | Disable code linting with ESLint.
381 |
382 | #### babelHelpers
383 |
384 | - **Type**: `'bundled' | 'runtime'`
385 | - **Default**: `bundled`
386 |
387 | How Babel helpers are inserted into the Rollup bundle. If you select `runtime`, then you must add [@babel/runtime](https://www.npmjs.com/package/@babel/runtime) as a dependency to your package.json.
388 |
389 | > Note: Babel helpers for UMD module format are always bundled.
390 |
391 | #### rollupOptions
392 |
393 | - **Type**: `RollupOptions | ((config: RollupOptions, options) => RollupOptions)`
394 |
395 | Directly customize the underlying Rollup bundle. These options will be merged with Create React Package's internal Rollup options. See [Rollup options docs](https://rollupjs.org/guide/en/#big-list-of-options) for more details.
396 |
397 | #### playground.server
398 |
399 | - **Type**: `RollupServeOptions`
400 |
401 | Development server configuration. See options [here](https://github.com/thgh/rollup-plugin-serve#options)
402 |
403 | #### playground.livereload
404 |
405 | - **Type**: `RollupLivereloadOptions`
406 |
407 | Development server livereload configuration. See options [here](https://github.com/thgh/rollup-plugin-livereload#options)
408 |
409 | #### playground.rollupOptions
410 |
411 | - **Type**: `RollupOptions | ((config: RollupOptions) => RollupOptions)`
412 |
413 | Rollup options for playground app bundle. See [Rollup options docs](https://rollupjs.org/guide/en/#big-list-of-options) for more details.
414 |
415 | ### Rollup
416 |
417 | Create React Package uses Rollup to bundle your library. To customize the rollup configuration, create a file `crp.config.js` at the root of your package and pass any rollup options.
418 |
419 | ```js
420 | const { defineConfig } = require('react-pkg-scripts');
421 |
422 | module.exports = defineConfig({
423 | rollupOptions: {
424 | // rollup options
425 | },
426 | });
427 | ```
428 |
429 | #### Conditional Rollup Config
430 |
431 | If the config needs to conditionally determine options based on the module format or the mode being used, pass a function to `rollupOptions`.
432 |
433 | ```js
434 | const { defineConfig } = require('react-pkg-scripts');
435 |
436 | module.exports = defineConfig({
437 | rollupOptions: (config, { format, mode }) => {
438 | if (format === 'cjs' && mode === 'production') {
439 | // config options only for the CJS Production build
440 | }
441 | return config;
442 | },
443 | });
444 | ```
445 |
446 | #### Example: Import images
447 |
448 | To import and ship your package with JPG, PNG, GIF, SVG, and WebP files, use [@rollup/plugin-image](https://www.npmjs.com/package/@rollup/plugin-image). First, install it as a dev dependency
449 |
450 | ```sh
451 | npm i -D @rollup/plugin-image
452 | ```
453 |
454 | And use it in the `crp.config.js`
455 |
456 | ```js
457 | const { defineConfig } = require('react-pkg-scripts');
458 | const images = require('@rollup/plugin-image');
459 |
460 | module.exports = defineConfig({
461 | rollupOptions: {
462 | plugins: [images()],
463 | },
464 | });
465 | ```
466 |
467 | Now, you can import images like
468 |
469 | ```jsx
470 | import React from 'react';
471 | import image from './image.png';
472 |
473 | return ;
474 | ```
475 |
476 | > Note: If you are using TypeScript, create a folder and file `types/index.d.ts` at the root of your project with the following to make it work with TypeScript compiler.
477 |
478 | ```ts
479 | declare module '*.png';
480 | declare module '*.jpg';
481 | ```
482 |
483 | ### Babel
484 |
485 | Create React Package respects [Babel configuration files](https://babeljs.io/docs/en/config-files).
486 |
487 | #### Example: Optimize Lodash
488 |
489 | If you use a lodash function in your library like `import { cloneDeep } from 'lodash'` the compiled bundle will contain all of the lodash's library.
490 |
491 | Ideally, your compiled bundle should only contain what you use in the source of your library. Create React Package helps you do that with some Babel configuration.
492 |
493 | Install [lodash](https://www.npmjs.com/package/lodash) and [babel-plugin-import](https://www.npmjs.com/package/babel-plugin-import) in your package.
494 |
495 | ```sh
496 | npm i lodash
497 | npm i -D babel-plugin-import
498 | ```
499 |
500 | Create a file `.babelrc` at the root of your project with the following.
501 |
502 | ```json
503 | {
504 | "plugins": [
505 | [
506 | "import",
507 | {
508 | "libraryName": "lodash",
509 | "libraryDirectory": "",
510 | "camel2DashComponentName": false
511 | }
512 | ]
513 | ]
514 | }
515 | ```
516 |
517 | This Babel configuration will be merged with Create React Package's internal config. Now, your bundle will not include all lodash functions, just the functions you import into your project.
518 |
519 | ### ESLint
520 |
521 | Create React Package respects [ESLint configuration files](https://eslint.org/docs/latest/user-guide/configuring/configuration-files).
522 |
523 | To disable linting, pass `disableESLint: true` option to `crp.config.js`
524 |
525 | ```js
526 | const { defineConfig } = require('react-pkg-scripts');
527 |
528 | module.exports = defineConfig({
529 | disableESLint: true,
530 | });
531 | ```
532 |
533 | To ignore any files, create a `.eslintignore` file at the root of the package.
534 |
535 | ### Jest
536 |
537 | Create React Package executes the following files with Jest test runner:
538 |
539 | - Files with `.js` suffix in `__tests__` folders. (under any level, not only in src)
540 | - Files with `.test.js` suffix.
541 | - Files with `.spec.js` suffix.
542 |
543 | > Note: `.js`, `.jsx`, `.ts`, `.tsx` file extensions are supported.
544 |
545 | You can override Create React Package's [default Jest configuration](https://github.com/haseebanwar/create-react-pkg/blob/master/packages/react-pkg-scripts/src/scripts/test.js) by adding any of the [Jest Options](https://jestjs.io/docs/27.x/configuration#options) to package.json.
546 |
547 | Example package.json
548 |
549 | ```json
550 | {
551 | "name": "your-package",
552 | "jest": {
553 | "collectCoverage": true,
554 | "collectCoverageFrom": [
555 | "**/*.{js,jsx}",
556 | "!**/node_modules/**",
557 | "!**/vendor/**"
558 | ]
559 | }
560 | }
561 | ```
562 |
563 | Note that this config is shallow merged.
564 |
565 | #### CLI Options
566 |
567 | You can pass [Jest CLI options](https://jestjs.io/docs/27.x/cli) to the `test` script in your package.json.
568 |
569 | ```diff
570 | "scripts": {
571 | - "test": "react-pkg-scripts test"
572 | + "test": "react-pkg-scripts test --watchAll"
573 | }
574 | ```
575 |
576 | ## Styling
577 |
578 | Create React Package lets you ship your package with CSS assets. You can import stylesheets in your JavaScript files straight away without doing any additional setup.
579 |
580 | ```css
581 | /* Button.css */
582 |
583 | .Button {
584 | padding: 15px;
585 | }
586 | ```
587 |
588 | And then in your JavaScript file
589 |
590 | ```jsx
591 | // Button.js
592 |
593 | import React from 'react';
594 | import './Button.css';
595 |
596 | const Button = () => {
597 | return ;
598 | };
599 | ```
600 |
601 | Create React Package concatenates all your stylesheets into a single minified `.css` file and places it in the build output.
602 |
603 | > Tip: CSS Modules are also supported.
604 |
605 | ### Sass/Stylus/Less Files
606 |
607 | - For Sass, install [sass](https://www.npmjs.com/package/sass): `npm i -D sass`
608 | - For Stylus, install [stylus](https://www.npmjs.com/package/stylus): `npm i -D stylus`
609 | - For Less, install [less](https://www.npmjs.com/package/less): `npm i -D less`
610 |
611 | That's it, you can now import `.styl` `.scss` `.sass` `.less` files in your project.
612 |
613 | ### Post-Processing CSS
614 |
615 | This project uses [rollup-plugin-postcss
616 | ](https://www.npmjs.com/package/rollup-plugin-postcss) that integrates Rollup with [PostCSS](https://github.com/postcss/postcss). In addition to that, it adds vendor prefixes automatically to the bundled CSS through [Autoprefixer](https://github.com/postcss/autoprefixer) so you don’t need to worry about it.
617 |
618 | You can customize your target support browsers by adjusting the `browserslist` key in package.json. You can read more about Browserslist configuration [here](#configure-supported-browsers).
619 |
620 | For example, this:
621 |
622 | ```css
623 | div {
624 | user-select: none;
625 | }
626 | ```
627 |
628 | is transformed into this:
629 |
630 | ```css
631 | div {
632 | -webkit-user-select: none;
633 | user-select: none;
634 | }
635 | ```
636 |
637 | If you need to disable autoprefixing, follow [autoprefixer disabling section](https://github.com/postcss/autoprefixer#disabling).
638 |
639 | ## Advanced Usage
640 |
641 | ### Code Splitting
642 |
643 | It is recommended that you do code splitting in your app and not in the library. But if you still need to code split your library for some reason, Create React Package got your back.
644 |
645 | This project supports code splitting via dynamic `import()`.
646 |
647 | For example:
648 |
649 | ```js
650 | // greeting.js
651 |
652 | const greeting = 'Hi there!';
653 |
654 | export { greeting };
655 | ```
656 |
657 | ```jsx
658 | // index.js
659 |
660 | import React from 'react';
661 |
662 | const MyComponent = () => {
663 | const handleClick = async () => {
664 | try {
665 | const { greeting } = await import('./greeting');
666 | console.log(greeting); // prints: Hi there!
667 | } catch (error) {
668 | // handle failure
669 | }
670 | };
671 |
672 | return ;
673 | };
674 | ```
675 |
676 | You can also use React `lazy` and `Suspense` to load components lazily.
677 |
678 | > Note: Code-splitting is not supported for UMD format.
679 |
680 | ### Configure Supported Browsers
681 |
682 | Create React Package uses [Browserslist](https://github.com/browserslist/browserslist) to target a broad range of browsers. By default, the generated project includes the following Browserslist configuration in package.json.
683 |
684 | ```json
685 | "browserslist": {
686 | "production": [
687 | ">0.2%",
688 | "not dead",
689 | "not op_mini all"
690 | ],
691 | "development": [
692 | "last 1 chrome version",
693 | "last 1 firefox version",
694 | "last 1 safari version"
695 | ]
696 | },
697 | ```
698 |
699 | The `browserslist` configuration controls the outputted JavaScript and CSS so that the emitted code will be compatible with the browsers specified. The `production` list will be used when creating a production build with the `build` script, and the `development` list will be used with the `watch` script.
700 |
701 | You can adjust this configuration according to the [Browserslist specification](https://github.com/browserslist/browserslist#readme).
702 |
703 | > Note: This configuration does not include polyfills automatically.
704 |
705 | ## Author
706 |
707 | - [Haseeb Anwar](https://haseebanwar.net/)
708 |
709 | ## License
710 |
711 | Create React Package is open-source software [licensed as MIT](https://github.com/haseebanwar/create-react-pkg/blob/master/LICENSE).
712 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "targets": {
3 | "node": 14
4 | },
5 | "presets": ["@babel/preset-env"],
6 | "plugins": ["@babel/transform-runtime"]
7 | }
8 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'node',
3 | testMatch: ['/**/*.test.js'],
4 | testPathIgnorePatterns: ['/templates/', '/node_modules/'],
5 | };
6 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "independent"
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "lerna run start --stream",
5 | "build": "lerna run build",
6 | "test": "jest",
7 | "lint": "eslint packages",
8 | "release": "lerna publish"
9 | },
10 | "devDependencies": {
11 | "@babel/cli": "^7.19.3",
12 | "@babel/core": "^7.19.3",
13 | "@babel/plugin-transform-runtime": "^7.19.1",
14 | "@babel/preset-env": "^7.19.4",
15 | "babel-jest": "^27.5.1",
16 | "eslint": "^8.25.0",
17 | "jest": "^27.5.1",
18 | "lerna": "^6.0.1",
19 | "rimraf": "^3.0.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-present Haseeb Anwar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/README.md:
--------------------------------------------------------------------------------
1 | # create-react-pkg
2 |
3 | This package includes the global command for [Create React Package](https://github.com/haseebanwar/create-react-pkg). A zero-config CLI for creating react packages.
4 |
5 | Please refer to its documentation:
6 |
7 | - [Getting Started](https://github.com/haseebanwar/create-react-pkg) – How to create a new package.
8 | - [User Guide](https://github.com/haseebanwar/create-react-pkg) – How to develop packages bootstrapped with Create React Package.
9 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-react-pkg",
3 | "version": "1.0.6",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "create-react-pkg",
9 | "version": "1.0.6",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@babel/runtime": "^7.19.4",
13 | "chalk": "^4.1.2",
14 | "commander": "^9.0.0",
15 | "cross-spawn": "^7.0.3",
16 | "fs-extra": "^10.1.0",
17 | "prompts": "^2.4.2",
18 | "semver": "^7.3.8",
19 | "validate-npm-package-name": "^4.0.0"
20 | },
21 | "bin": {
22 | "create-react-pkg": "lib/index.js"
23 | },
24 | "engines": {
25 | "node": ">=14.17.0"
26 | }
27 | },
28 | "node_modules/@babel/runtime": {
29 | "version": "7.19.4",
30 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz",
31 | "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==",
32 | "dependencies": {
33 | "regenerator-runtime": "^0.13.4"
34 | },
35 | "engines": {
36 | "node": ">=6.9.0"
37 | }
38 | },
39 | "node_modules/ansi-styles": {
40 | "version": "4.3.0",
41 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
42 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
43 | "dependencies": {
44 | "color-convert": "^2.0.1"
45 | },
46 | "engines": {
47 | "node": ">=8"
48 | },
49 | "funding": {
50 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
51 | }
52 | },
53 | "node_modules/builtins": {
54 | "version": "5.0.1",
55 | "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
56 | "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
57 | "dependencies": {
58 | "semver": "^7.0.0"
59 | }
60 | },
61 | "node_modules/chalk": {
62 | "version": "4.1.2",
63 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
64 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
65 | "dependencies": {
66 | "ansi-styles": "^4.1.0",
67 | "supports-color": "^7.1.0"
68 | },
69 | "engines": {
70 | "node": ">=10"
71 | },
72 | "funding": {
73 | "url": "https://github.com/chalk/chalk?sponsor=1"
74 | }
75 | },
76 | "node_modules/color-convert": {
77 | "version": "2.0.1",
78 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
79 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
80 | "dependencies": {
81 | "color-name": "~1.1.4"
82 | },
83 | "engines": {
84 | "node": ">=7.0.0"
85 | }
86 | },
87 | "node_modules/color-name": {
88 | "version": "1.1.4",
89 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
90 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
91 | },
92 | "node_modules/commander": {
93 | "version": "9.3.0",
94 | "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
95 | "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==",
96 | "engines": {
97 | "node": "^12.20.0 || >=14"
98 | }
99 | },
100 | "node_modules/cross-spawn": {
101 | "version": "7.0.3",
102 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
103 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
104 | "dependencies": {
105 | "path-key": "^3.1.0",
106 | "shebang-command": "^2.0.0",
107 | "which": "^2.0.1"
108 | },
109 | "engines": {
110 | "node": ">= 8"
111 | }
112 | },
113 | "node_modules/fs-extra": {
114 | "version": "10.1.0",
115 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
116 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
117 | "dependencies": {
118 | "graceful-fs": "^4.2.0",
119 | "jsonfile": "^6.0.1",
120 | "universalify": "^2.0.0"
121 | },
122 | "engines": {
123 | "node": ">=12"
124 | }
125 | },
126 | "node_modules/graceful-fs": {
127 | "version": "4.2.10",
128 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
129 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
130 | },
131 | "node_modules/has-flag": {
132 | "version": "4.0.0",
133 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
134 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
135 | "engines": {
136 | "node": ">=8"
137 | }
138 | },
139 | "node_modules/isexe": {
140 | "version": "2.0.0",
141 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
142 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
143 | },
144 | "node_modules/jsonfile": {
145 | "version": "6.1.0",
146 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
147 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
148 | "dependencies": {
149 | "universalify": "^2.0.0"
150 | },
151 | "optionalDependencies": {
152 | "graceful-fs": "^4.1.6"
153 | }
154 | },
155 | "node_modules/kleur": {
156 | "version": "3.0.3",
157 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
158 | "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
159 | "engines": {
160 | "node": ">=6"
161 | }
162 | },
163 | "node_modules/lru-cache": {
164 | "version": "6.0.0",
165 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
166 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
167 | "dependencies": {
168 | "yallist": "^4.0.0"
169 | },
170 | "engines": {
171 | "node": ">=10"
172 | }
173 | },
174 | "node_modules/path-key": {
175 | "version": "3.1.1",
176 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
177 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
178 | "engines": {
179 | "node": ">=8"
180 | }
181 | },
182 | "node_modules/prompts": {
183 | "version": "2.4.2",
184 | "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
185 | "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
186 | "dependencies": {
187 | "kleur": "^3.0.3",
188 | "sisteransi": "^1.0.5"
189 | },
190 | "engines": {
191 | "node": ">= 6"
192 | }
193 | },
194 | "node_modules/regenerator-runtime": {
195 | "version": "0.13.9",
196 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
197 | "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
198 | },
199 | "node_modules/semver": {
200 | "version": "7.3.8",
201 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
202 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
203 | "dependencies": {
204 | "lru-cache": "^6.0.0"
205 | },
206 | "bin": {
207 | "semver": "bin/semver.js"
208 | },
209 | "engines": {
210 | "node": ">=10"
211 | }
212 | },
213 | "node_modules/shebang-command": {
214 | "version": "2.0.0",
215 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
216 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
217 | "dependencies": {
218 | "shebang-regex": "^3.0.0"
219 | },
220 | "engines": {
221 | "node": ">=8"
222 | }
223 | },
224 | "node_modules/shebang-regex": {
225 | "version": "3.0.0",
226 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
227 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
228 | "engines": {
229 | "node": ">=8"
230 | }
231 | },
232 | "node_modules/sisteransi": {
233 | "version": "1.0.5",
234 | "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
235 | "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
236 | },
237 | "node_modules/supports-color": {
238 | "version": "7.2.0",
239 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
240 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
241 | "dependencies": {
242 | "has-flag": "^4.0.0"
243 | },
244 | "engines": {
245 | "node": ">=8"
246 | }
247 | },
248 | "node_modules/universalify": {
249 | "version": "2.0.0",
250 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
251 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
252 | "engines": {
253 | "node": ">= 10.0.0"
254 | }
255 | },
256 | "node_modules/validate-npm-package-name": {
257 | "version": "4.0.0",
258 | "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz",
259 | "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==",
260 | "dependencies": {
261 | "builtins": "^5.0.0"
262 | },
263 | "engines": {
264 | "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
265 | }
266 | },
267 | "node_modules/which": {
268 | "version": "2.0.2",
269 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
270 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
271 | "dependencies": {
272 | "isexe": "^2.0.0"
273 | },
274 | "bin": {
275 | "node-which": "bin/node-which"
276 | },
277 | "engines": {
278 | "node": ">= 8"
279 | }
280 | },
281 | "node_modules/yallist": {
282 | "version": "4.0.0",
283 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
284 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
285 | }
286 | },
287 | "dependencies": {
288 | "@babel/runtime": {
289 | "version": "7.19.4",
290 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz",
291 | "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==",
292 | "requires": {
293 | "regenerator-runtime": "^0.13.4"
294 | }
295 | },
296 | "ansi-styles": {
297 | "version": "4.3.0",
298 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
299 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
300 | "requires": {
301 | "color-convert": "^2.0.1"
302 | }
303 | },
304 | "builtins": {
305 | "version": "5.0.1",
306 | "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
307 | "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
308 | "requires": {
309 | "semver": "^7.0.0"
310 | }
311 | },
312 | "chalk": {
313 | "version": "4.1.2",
314 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
315 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
316 | "requires": {
317 | "ansi-styles": "^4.1.0",
318 | "supports-color": "^7.1.0"
319 | }
320 | },
321 | "color-convert": {
322 | "version": "2.0.1",
323 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
324 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
325 | "requires": {
326 | "color-name": "~1.1.4"
327 | }
328 | },
329 | "color-name": {
330 | "version": "1.1.4",
331 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
332 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
333 | },
334 | "commander": {
335 | "version": "9.3.0",
336 | "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
337 | "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw=="
338 | },
339 | "cross-spawn": {
340 | "version": "7.0.3",
341 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
342 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
343 | "requires": {
344 | "path-key": "^3.1.0",
345 | "shebang-command": "^2.0.0",
346 | "which": "^2.0.1"
347 | }
348 | },
349 | "fs-extra": {
350 | "version": "10.1.0",
351 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
352 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
353 | "requires": {
354 | "graceful-fs": "^4.2.0",
355 | "jsonfile": "^6.0.1",
356 | "universalify": "^2.0.0"
357 | }
358 | },
359 | "graceful-fs": {
360 | "version": "4.2.10",
361 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
362 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
363 | },
364 | "has-flag": {
365 | "version": "4.0.0",
366 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
367 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
368 | },
369 | "isexe": {
370 | "version": "2.0.0",
371 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
372 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
373 | },
374 | "jsonfile": {
375 | "version": "6.1.0",
376 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
377 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
378 | "requires": {
379 | "graceful-fs": "^4.1.6",
380 | "universalify": "^2.0.0"
381 | }
382 | },
383 | "kleur": {
384 | "version": "3.0.3",
385 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
386 | "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
387 | },
388 | "lru-cache": {
389 | "version": "6.0.0",
390 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
391 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
392 | "requires": {
393 | "yallist": "^4.0.0"
394 | }
395 | },
396 | "path-key": {
397 | "version": "3.1.1",
398 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
399 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
400 | },
401 | "prompts": {
402 | "version": "2.4.2",
403 | "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
404 | "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
405 | "requires": {
406 | "kleur": "^3.0.3",
407 | "sisteransi": "^1.0.5"
408 | }
409 | },
410 | "regenerator-runtime": {
411 | "version": "0.13.9",
412 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
413 | "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
414 | },
415 | "semver": {
416 | "version": "7.3.8",
417 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
418 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
419 | "requires": {
420 | "lru-cache": "^6.0.0"
421 | }
422 | },
423 | "shebang-command": {
424 | "version": "2.0.0",
425 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
426 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
427 | "requires": {
428 | "shebang-regex": "^3.0.0"
429 | }
430 | },
431 | "shebang-regex": {
432 | "version": "3.0.0",
433 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
434 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
435 | },
436 | "sisteransi": {
437 | "version": "1.0.5",
438 | "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
439 | "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
440 | },
441 | "supports-color": {
442 | "version": "7.2.0",
443 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
444 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
445 | "requires": {
446 | "has-flag": "^4.0.0"
447 | }
448 | },
449 | "universalify": {
450 | "version": "2.0.0",
451 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
452 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
453 | },
454 | "validate-npm-package-name": {
455 | "version": "4.0.0",
456 | "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz",
457 | "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==",
458 | "requires": {
459 | "builtins": "^5.0.0"
460 | }
461 | },
462 | "which": {
463 | "version": "2.0.2",
464 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
465 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
466 | "requires": {
467 | "isexe": "^2.0.0"
468 | }
469 | },
470 | "yallist": {
471 | "version": "4.0.0",
472 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
473 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
474 | }
475 | }
476 | }
477 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-react-pkg",
3 | "version": "1.0.6",
4 | "description": "Zero config CLI for creating react packages",
5 | "keywords": [
6 | "react",
7 | "cli",
8 | "package",
9 | "library",
10 | "rollup"
11 | ],
12 | "homepage": "https://github.com/haseebanwar/create-react-pkg/tree/master/packages/create-react-pkg",
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/haseebanwar/create-react-pkg.git",
16 | "directory": "packages/create-react-pkg"
17 | },
18 | "bugs": {
19 | "url": "https://github.com/haseebanwar/create-react-pkg/issues"
20 | },
21 | "author": "Haseeb Anwar (https://haseebanwar.net/)",
22 | "license": "MIT",
23 | "bin": {
24 | "create-react-pkg": "lib/index.js"
25 | },
26 | "files": [
27 | "lib",
28 | "templates"
29 | ],
30 | "engines": {
31 | "node": ">=14.17.0"
32 | },
33 | "scripts": {
34 | "start": "npm run clean && babel src -d lib --root-mode upward --watch",
35 | "build": "npm run clean && babel src -d lib --root-mode upward",
36 | "prepublishOnly": "npm run build",
37 | "clean": "rimraf lib"
38 | },
39 | "dependencies": {
40 | "@babel/runtime": "^7.19.4",
41 | "chalk": "^4.1.2",
42 | "commander": "^9.0.0",
43 | "cross-spawn": "^7.0.3",
44 | "fs-extra": "^10.1.0",
45 | "prompts": "^2.4.2",
46 | "semver": "^7.3.8",
47 | "validate-npm-package-name": "^4.0.0"
48 | },
49 | "gitHead": "8d5e7ac1c028829aa70e4ae1256141679b21167b"
50 | }
51 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/src/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import path from 'path';
4 | import semver from 'semver';
5 | import fs from 'fs-extra';
6 | import { program } from 'commander';
7 | import prompts from 'prompts';
8 | import chalk from 'chalk';
9 | import validatePackageName from 'validate-npm-package-name';
10 | import {
11 | checkForLatestVersion,
12 | getAuthorName,
13 | composePackageJSON,
14 | isUsingYarn,
15 | makePackageDeps,
16 | makeInstallArgs,
17 | getTemplateName,
18 | sanitizePackageName,
19 | executeInstallCommand,
20 | getNPMVersion,
21 | setLegacyPeerDeps,
22 | } from './utils';
23 | import packageJSON from '../package.json';
24 |
25 | program.name(packageJSON.name);
26 | program.version(packageJSON.version);
27 |
28 | program
29 | .argument('[package-directory]')
30 | .usage(`${chalk.green('')} [options]`)
31 | .option('--ts, --typescript', 'initialize a typescript package')
32 | .option('--sb, --storybook', 'add storybook')
33 | .action(async (projectDirectory, flags) => {
34 | try {
35 | // prompt if package directory is not specified
36 | if (!projectDirectory) {
37 | const projectDirectoryInput = await prompts(
38 | {
39 | type: 'text',
40 | name: 'projectDirectory',
41 | message: 'What is your package named?',
42 | initial: 'my-package',
43 | },
44 | {
45 | onCancel: () => {
46 | console.log('Please specify the package directory');
47 | console.log(
48 | ` ${chalk.cyan(program.name())} ${chalk.green(
49 | ``
50 | )}`
51 | );
52 |
53 | console.log('\nFor example:');
54 | console.log(
55 | ` ${chalk.cyan(program.name())} ${chalk.green(`my-package`)}`
56 | );
57 |
58 | console.log(
59 | `\nRun ${chalk.cyan(
60 | `${program.name()} --help`
61 | )} to see all options.`
62 | );
63 |
64 | process.exit(1);
65 | },
66 | }
67 | );
68 | projectDirectory = projectDirectoryInput.projectDirectory;
69 | }
70 |
71 | // check if user is on non-supported node version
72 | const currentNodeVersion = process.versions.node;
73 | const packageNodeVersion = packageJSON.engines.node;
74 | if (!semver.satisfies(currentNodeVersion, packageNodeVersion)) {
75 | console.error(
76 | `You are running Node ${currentNodeVersion}.\nCreate React Package requires Node ${
77 | semver.minVersion(packageNodeVersion).version
78 | } or higher.\nPlease update your version of Node.`
79 | );
80 | process.exit(1);
81 | }
82 |
83 | const { storybook, typescript } = flags;
84 |
85 | const projectPath = path.resolve(projectDirectory);
86 | const packageName = sanitizePackageName(path.basename(projectPath));
87 |
88 | // validate package name
89 | const {
90 | validForNewPackages,
91 | errors: packageNameErrors,
92 | warnings: packageNameWarnings,
93 | } = validatePackageName(packageName);
94 |
95 | if (!validForNewPackages) {
96 | console.error(
97 | chalk.red(`Invalid package name ${chalk.cyan(`"${packageName}"`)}`)
98 | );
99 |
100 | [...(packageNameErrors || []), ...(packageNameWarnings || [])].forEach(
101 | (error) => {
102 | console.log(chalk.red(` - ${error}`));
103 | }
104 | );
105 | console.log('\nPlease use a different package name');
106 | process.exit(1);
107 | }
108 |
109 | // create package directory if it doesn't exist
110 | fs.ensureDirSync(projectPath);
111 |
112 | // throw an error if package folder contains files except valid files
113 | const validFiles = [
114 | '.DS_Store',
115 | '.git',
116 | '.gitattributes',
117 | '.gitignore',
118 | '.gitlab-ci.yml',
119 | '.hg',
120 | '.hgcheck',
121 | '.hgignore',
122 | '.idea',
123 | '.npmignore',
124 | '.travis.yml',
125 | 'docs',
126 | 'mkdocs.yml',
127 | 'Thumbs.db',
128 | ];
129 | const files = fs
130 | .readdirSync(projectPath)
131 | .filter((file) => !validFiles.includes(file));
132 | if (files.length) {
133 | console.error(
134 | chalk.red(
135 | `Please make sure that your package directory ${chalk.cyan(
136 | `"${packageName}"`
137 | )} is empty.\nRemove any hidden directories/files as well.`
138 | )
139 | );
140 | process.exit(1);
141 | }
142 |
143 | // check if user is creating a new package with an old version of CLI
144 | try {
145 | const latestVersionOfCLI = await checkForLatestVersion();
146 |
147 | if (
148 | latestVersionOfCLI &&
149 | semver.lt(packageJSON.version, latestVersionOfCLI)
150 | ) {
151 | console.error(
152 | chalk.red(
153 | `You are running \`create-react-pkg\` ${chalk.cyan(
154 | packageJSON.version
155 | )} which is behind the latest release ${chalk.cyan(
156 | latestVersionOfCLI
157 | )}`
158 | )
159 | );
160 | console.log(
161 | '\nPlease remove any global installs with one of the following commands:\n' +
162 | `- npm uninstall -g ${packageJSON.name}\n` +
163 | `- yarn global remove ${packageJSON.name}`
164 | );
165 | console.log(
166 | '\nThe latest instructions for creating a new package can be found here:\n' +
167 | 'https://github.com/haseebanwar/create-react-pkg#getting-started'
168 | );
169 | process.exit(1);
170 | }
171 | } catch (error) {
172 | // ignore and let user continue with old version
173 | }
174 |
175 | // start creation of package
176 | console.log(
177 | `\nCreating a new package ${chalk.green(packageName)} in ${chalk.green(
178 | projectPath
179 | )}`
180 | );
181 |
182 | const template = getTemplateName(typescript, storybook);
183 |
184 | // copy the template
185 | await fs.copy(
186 | path.resolve(__dirname, `../templates/${template}`),
187 | projectPath
188 | );
189 |
190 | // copy base files
191 | await fs.copy(
192 | path.resolve(__dirname, '../templates/baseFiles'),
193 | projectPath
194 | );
195 |
196 | // fix gitignore
197 | await fs.move(
198 | path.resolve(projectPath, './gitignore'),
199 | path.resolve(projectPath, './.gitignore')
200 | );
201 |
202 | // get author name
203 | let author = getAuthorName();
204 |
205 | // prompt to get author name if not present
206 | if (!author) {
207 | const authorInput = await prompts({
208 | type: 'text',
209 | name: 'author',
210 | message: 'Package author',
211 | });
212 |
213 | author = authorInput.author;
214 | }
215 |
216 | // fix license
217 | const licensePath = path.resolve(projectPath, 'LICENSE');
218 | let license = fs.readFileSync(licensePath, { encoding: 'utf-8' });
219 |
220 | license = license.replace(/\[year\]/g, new Date().getFullYear());
221 | license = license.replace(/\[author\]/g, author);
222 | fs.writeFileSync(licensePath, license, { encoding: 'utf-8' });
223 |
224 | // generate package.json
225 | const pkg = composePackageJSON(
226 | packageName,
227 | author,
228 | typescript,
229 | storybook
230 | );
231 | fs.outputJSONSync(path.resolve(projectPath, 'package.json'), pkg, {
232 | spaces: 2,
233 | });
234 |
235 | // decide whether to use npm or yarn for installing deps
236 | const useYarn = isUsingYarn();
237 | const packageManager = useYarn ? 'yarn' : 'npm';
238 |
239 | // if user is setting up storybook with npm v7+, use legacy peer deps until storybook 7 is released
240 | // more https://github.com/storybookjs/storybook/issues/18298#issuecomment-1136158953
241 | let useLegacyPeerDeps = false;
242 | let setNPMRCForLegacyPeerDeps = false;
243 | if (packageManager === 'npm' && storybook) {
244 | const npmVersion = getNPMVersion();
245 |
246 | if (semver.gte(npmVersion, '7.0.0')) {
247 | // use legacy peer deps (for this install) even if user says no to the prompt below
248 | useLegacyPeerDeps = true;
249 |
250 | console.log(
251 | `\nWe've detected you are running npm version ${chalk.cyan(
252 | npmVersion
253 | )} which has peer dependency semantics which Storybook is incompatible with.`
254 | );
255 | console.log(
256 | `In order to work with Storybook's package structure, you'll need to run \`npm\` with the \`--legacy-peer-deps=true\` flag`
257 | );
258 | console.log(
259 | `\nMore info: ${chalk.yellow(
260 | 'https://github.com/storybookjs/storybook/issues/18298'
261 | )}\n`
262 | );
263 |
264 | const legacyPeerDepsInput = await prompts({
265 | type: 'confirm',
266 | name: 'setNPMRCForLegacyPeerDeps',
267 | message: `Generate an \`.npmrc\` to run \`npm\` with the \`--legacy-peer-deps=true\` flag?`,
268 | initial: true,
269 | });
270 |
271 | setNPMRCForLegacyPeerDeps =
272 | legacyPeerDepsInput.setNPMRCForLegacyPeerDeps;
273 | }
274 | }
275 |
276 | console.log(
277 | '\nInstalling dependencies. This might take a couple of minutes.'
278 | );
279 | console.log(
280 | `Installing ${chalk.cyan('react')}, ${chalk.cyan(
281 | 'react-dom'
282 | )}, and ${chalk.cyan('react-pkg-scripts')}${
283 | typescript || storybook ? ' with' : ''
284 | }`
285 | );
286 | typescript && console.log(`- ${chalk.cyan('typescript')}`);
287 | storybook && console.log(`- ${chalk.cyan('storybook')}`);
288 | useYarn && console.log(''); // line break for yarn only
289 |
290 | // install deps
291 | const dependencies = makePackageDeps(typescript, storybook);
292 | process.chdir(projectPath);
293 |
294 | if (setNPMRCForLegacyPeerDeps) {
295 | setLegacyPeerDeps();
296 | }
297 |
298 | const installArgs = makeInstallArgs(
299 | packageManager,
300 | dependencies,
301 | useLegacyPeerDeps
302 | );
303 | await executeInstallCommand(packageManager, installArgs);
304 |
305 | console.log('\nInstalled dependencies');
306 |
307 | console.log(`\nSuccess! Created ${packageName} at ${projectPath}`);
308 | console.log(
309 | 'Inside that directory, you can run the following commands:\n'
310 | );
311 |
312 | console.log(chalk.cyan(` ${packageManager} start`));
313 | console.log(' Watches for changes as you build.\n');
314 |
315 | console.log(
316 | chalk.cyan(
317 | ` ${packageManager}${packageManager === 'npm' ? ' run' : ''} build`
318 | )
319 | );
320 | console.log(' Creates an optimized production build.\n');
321 |
322 | console.log(chalk.cyan(` ${packageManager} test`));
323 | console.log(' Runs tests with Jest.\n');
324 |
325 | console.log('Build Something Great!');
326 |
327 | process.exit(0);
328 | } catch (error) {
329 | console.error(chalk.red(`Failed to create package: ${error.message}`));
330 | console.log('error', error);
331 | process.exit(1);
332 | }
333 | });
334 |
335 | program.parse(process.argv);
336 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/src/pkgTemplate.js:
--------------------------------------------------------------------------------
1 | // name and author fields will be dynamic
2 | export const basePackageJSON = {
3 | version: '0.1.0',
4 | description: '',
5 | files: ['dist'],
6 | license: 'MIT',
7 | scripts: {
8 | start: `react-pkg-scripts watch`,
9 | build: `react-pkg-scripts build`,
10 | test: `react-pkg-scripts test`,
11 | preview: `react-pkg-scripts preview`,
12 | },
13 | peerDependencies: {
14 | react: '>=17',
15 | 'react-dom': '>=17',
16 | },
17 | peerDependenciesMeta: {
18 | 'react-dom': {
19 | optional: true,
20 | },
21 | },
22 | keywords: ['react'],
23 | eslintConfig: {
24 | extends: ['react-app', 'react-app/jest'],
25 | },
26 | browserslist: {
27 | production: ['>0.2%', 'not dead', 'not op_mini all'],
28 | development: [
29 | 'last 1 chrome version',
30 | 'last 1 firefox version',
31 | 'last 1 safari version',
32 | ],
33 | },
34 | };
35 |
36 | export const dependencies = ['react-pkg-scripts', 'react', 'react-dom'];
37 | export const tsDependencies = [
38 | '@types/react',
39 | '@types/react-dom',
40 | '@types/jest@^27',
41 | '@types/node',
42 | // TODO: remove hard-coded version when this is fixed
43 | // https://github.com/facebook/create-react-app/issues/12150
44 | 'typescript@~4.5.0',
45 | 'tslib',
46 | 'ts-jest@^27',
47 | ];
48 | export const storybookDependencies = [
49 | '@babel/core',
50 | '@storybook/addon-actions',
51 | '@storybook/addon-essentials',
52 | '@storybook/addon-interactions',
53 | '@storybook/addon-links',
54 | '@storybook/builder-webpack4',
55 | '@storybook/manager-webpack4',
56 | '@storybook/react',
57 | '@storybook/testing-library',
58 | 'babel-loader',
59 | ];
60 | export const tsStorybookDependencies = ['@types/babel__core'];
61 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/src/utils.js:
--------------------------------------------------------------------------------
1 | import https from 'https';
2 | import { execSync } from 'child_process';
3 | import spawn from 'cross-spawn';
4 | import {
5 | basePackageJSON,
6 | dependencies,
7 | tsDependencies,
8 | storybookDependencies,
9 | tsStorybookDependencies,
10 | } from './pkgTemplate';
11 | import packageJSON from '../package.json';
12 |
13 | export function checkForLatestVersion() {
14 | return new Promise((resolve, reject) => {
15 | https
16 | .get(
17 | `https://registry.npmjs.org/-/package/${packageJSON.name}/dist-tags`,
18 | (res) => {
19 | if (res.statusCode === 200) {
20 | let body = '';
21 | res.on('data', (data) => (body += data));
22 | res.on('end', () => {
23 | resolve(JSON.parse(body).latest);
24 | });
25 | } else {
26 | reject(new Error('Failed to check for the latest version of CLI'));
27 | }
28 | }
29 | )
30 | .on('error', () => {
31 | reject(new Error('Failed to check for the latest version of CLI'));
32 | });
33 | });
34 | }
35 |
36 | export function getTemplateName(useTypescript, useStorybook) {
37 | if (useTypescript && useStorybook) {
38 | return 'typescript-storybook';
39 | } else if (useTypescript) {
40 | return 'typescript';
41 | } else if (useStorybook) {
42 | return 'basic-storybook';
43 | }
44 |
45 | return 'basic';
46 | }
47 |
48 | export function getAuthorName() {
49 | let author = '';
50 |
51 | author = execSync('npm config get init-author-name').toString().trim();
52 | if (author) return author;
53 |
54 | author = execSync('git config --global user.name').toString().trim();
55 | if (author) return author;
56 |
57 | return author;
58 | }
59 |
60 | export function sanitizePackageName(packageName) {
61 | return packageName
62 | .toLowerCase()
63 | .replace(/(^@.*\/)|((^[^a-z]+)|[^\w.-])|([^a-z0-9]+$)/g, '');
64 | }
65 |
66 | export function composePackageJSON(
67 | packageName,
68 | authorName,
69 | useTypescript,
70 | useStorybook
71 | ) {
72 | const safePackageName = sanitizePackageName(packageName);
73 | return {
74 | name: packageName,
75 | author: authorName,
76 | main: `dist/index.js`, // CJS entry
77 | module: `dist/esm/${safePackageName}.js`, // ES entry
78 | ...(useTypescript && {
79 | types: 'dist/types/index.d.ts',
80 | }),
81 | // spreading after so name fields appear above base fields in created package
82 | ...basePackageJSON,
83 | ...(useStorybook && {
84 | scripts: {
85 | ...basePackageJSON.scripts,
86 | storybook: 'start-storybook -p 6006',
87 | 'build-storybook': 'build-storybook',
88 | },
89 | }),
90 | };
91 | }
92 |
93 | export function getNPMVersion() {
94 | return execSync('npm --version').toString().trim();
95 | }
96 |
97 | export function setLegacyPeerDeps() {
98 | execSync('npm config set legacy-peer-deps=true --location=project');
99 | }
100 |
101 | // taken from create-react-app
102 | // https://github.com/facebook/create-react-app/blob/main/packages/create-react-app/createReactApp.js
103 | export function isUsingYarn() {
104 | return (process.env.npm_config_user_agent || '').indexOf('yarn') === 0;
105 | }
106 |
107 | export function makePackageDeps(useTypescript, useStorybook) {
108 | const deps = [...dependencies];
109 | if (useTypescript) {
110 | deps.push(...tsDependencies);
111 | }
112 | if (useStorybook) {
113 | deps.push(...storybookDependencies);
114 | if (useTypescript) deps.push(...tsStorybookDependencies);
115 | }
116 |
117 | return deps;
118 | }
119 |
120 | export function makeInstallArgs(cmd, dependencies, useLegacyPeerDeps) {
121 | switch (cmd) {
122 | case 'npm':
123 | return [
124 | 'install',
125 | ...dependencies,
126 | '--save-dev',
127 | '--no-audit', // https://github.com/facebook/create-react-app/issues/11174
128 | '--loglevel',
129 | 'error',
130 | useLegacyPeerDeps ? '--legacy-peer-deps' : '',
131 | ].filter(Boolean);
132 | case 'yarn':
133 | return ['add', ...dependencies, '--dev'];
134 | default:
135 | throw new Error('Unkown package manager');
136 | }
137 | }
138 |
139 | export function executeInstallCommand(command, args) {
140 | return new Promise((resolve, reject) => {
141 | const child = spawn(command, args, {
142 | stdio: 'inherit',
143 | });
144 | child.on('close', (code) => {
145 | if (code !== 0) {
146 | reject(new Error('Error installing dependencies'));
147 | return;
148 | }
149 | resolve();
150 | });
151 | });
152 | }
153 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/baseFiles/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [year] [author]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/baseFiles/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React Package
2 |
3 | This package was bootstrapped with [Create React Package](https://github.com/haseebanwar/create-react-pkg). A zero-config tool for creating React libraries.
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start` or `yarn start`
10 |
11 | Watches for changes and rebuilds. To see your bundled React component in a browser, use integrated playground with [npm run preview](#npm-run-preview-or-yarn-preview)
12 |
13 | Note that this build is not optimized. Use `npm run build` to create an optimized build.
14 |
15 | ### `npm test` or `yarn test`
16 |
17 | Runs tests with Jest.
18 |
19 | To launch the test runner in the interactive watch mode, change the `test` script in `package.json`
20 |
21 | ```diff
22 | "scripts": {
23 | - "test": "react-pkg-scripts test"
24 | + "test": "react-pkg-scripts test --watch"
25 | }
26 | ```
27 |
28 | ### `npm run build` or `yarn build`
29 |
30 | Builds the package for production to the `dist` folder. By default, it bundles your package in two module formats, CJS and ESM. But you can also create a UMD build by creating a file `crp.config.js` at the root of project with the following.
31 |
32 | ```js
33 | const { defineConfig } = require('react-pkg-scripts');
34 |
35 | module.exports = defineConfig({
36 | formats: ['cjs', 'esm', 'umd'],
37 | });
38 | ```
39 |
40 | ### `npm run preview` or `yarn preview`
41 |
42 | Opens React app development server from `playground/index.js` for previewing your library in browser. It comes with live reload that makes development much easier.
43 |
44 | Note that the integrated playground depends on the ESM output of your library. So, please run `npm start` with ESM build before running `npm run preview`
45 |
46 | ## Learn More
47 |
48 | You can learn more in the [Create React Package documentation](https://github.com/haseebanwar/create-react-pkg#readme).
49 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/baseFiles/gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # production
5 | /dist
6 |
7 | # misc
8 | .DS_Store
9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 |
14 | npm-debug.log*
15 | yarn-debug.log*
16 | yarn-error.log*
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/baseFiles/playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ${metas}
5 | Package Playground
6 | ${links}
7 |
8 |
9 |
10 | ${scripts}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/baseFiles/playground/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { MyComponent } from '../';
4 |
5 | const container = document.getElementById('root');
6 | const root = createRoot(container);
7 | root.render();
8 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/basic-storybook/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: [
3 | '../stories/**/*.stories.mdx',
4 | '../stories/**/*.stories.@(js|jsx|ts|tsx)',
5 | ],
6 | addons: [
7 | '@storybook/addon-links',
8 | '@storybook/addon-essentials',
9 | '@storybook/addon-interactions',
10 | ],
11 | framework: '@storybook/react',
12 | };
13 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/basic-storybook/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | export const parameters = {
2 | actions: { argTypesRegex: '^on[A-Z].*' },
3 | controls: {
4 | matchers: {
5 | color: /(background|color)$/i, // display a color picker for the args matching this regex
6 | date: /Date$/, // display a date picker for the args matching this regex
7 | },
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/packages/create-react-pkg/templates/basic-storybook/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const MyComponent = (props) => {
4 | return