├── .auto-changelog ├── .eslintignore ├── .eslintrc.js ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── SUPPORT.md └── workflows │ └── ci.yml ├── .gitignore ├── .huskyrc.js ├── .lintstagedrc.js ├── .neutrinorc.js ├── .prettierrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── api.md ├── assets │ └── logo.png ├── contributing │ ├── code-of-conduct.md │ ├── development.md │ └── index.md ├── creating-presets.md ├── customization.md ├── faq.md ├── index.md ├── installation │ ├── create-new-project.md │ └── index.md ├── learning-resources.md ├── middleware.md ├── migrate.md ├── migration-guide.md ├── packages │ ├── airbnb-base.md │ ├── airbnb.md │ ├── banner.md │ ├── clean.md │ ├── compile-loader.md │ ├── copy.md │ ├── dev-server.md │ ├── eslint.md │ ├── font-loader.md │ ├── html-loader.md │ ├── html-template.md │ ├── image-loader.md │ ├── jest.md │ ├── karma.md │ ├── library.md │ ├── mocha.md │ ├── node.md │ ├── preact.md │ ├── react-components.md │ ├── react.md │ ├── standardjs.md │ ├── start-server.md │ ├── style-loader.md │ ├── style-minify.md │ ├── vue.md │ └── web.md ├── presets.md ├── project-layout.md ├── requirements.txt ├── runtime.txt ├── usage.md └── webpack-chain.md ├── lerna.json ├── mkdocs.yml ├── netlify.toml ├── package.json ├── packages ├── airbnb-base │ ├── .npmignore │ ├── README.md │ ├── eslintrc.js │ ├── index.js │ ├── package.json │ └── test │ │ └── airbnb_test.js ├── airbnb │ ├── .npmignore │ ├── README.md │ ├── eslintrc.js │ ├── index.js │ ├── package.json │ └── test │ │ └── airbnb_test.js ├── banner │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── clean │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── compile-loader │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── copy │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── create-project │ ├── .npmignore │ ├── README.md │ ├── bin │ │ └── create-project.js │ ├── commands │ │ └── init │ │ │ ├── constants.js │ │ │ ├── index.js │ │ │ ├── templates │ │ │ ├── airbnb-base │ │ │ │ └── .eslintrc.js │ │ │ ├── airbnb │ │ │ │ └── .eslintrc.js │ │ │ ├── jest │ │ │ │ ├── jest.config.js │ │ │ │ └── test │ │ │ │ │ └── simple_test.js │ │ │ ├── karma │ │ │ │ ├── karma.conf.js │ │ │ │ └── test │ │ │ │ │ └── simple_test.js │ │ │ ├── library │ │ │ │ ├── src │ │ │ │ │ └── index.js │ │ │ │ └── webpack.config.js │ │ │ ├── mocha │ │ │ │ ├── .mocharc.js │ │ │ │ └── test │ │ │ │ │ └── simple_test.js │ │ │ ├── neutrino │ │ │ │ └── .neutrinorc.js.ejs │ │ │ ├── node │ │ │ │ ├── src │ │ │ │ │ ├── app.js │ │ │ │ │ └── index.js │ │ │ │ └── webpack.config.js │ │ │ ├── preact │ │ │ │ ├── src │ │ │ │ │ ├── App.css │ │ │ │ │ ├── App.jsx │ │ │ │ │ └── index.jsx │ │ │ │ └── webpack.config.js │ │ │ ├── react-components │ │ │ │ ├── src │ │ │ │ │ ├── components │ │ │ │ │ │ └── Example │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ └── index.jsx │ │ │ │ └── webpack.config.js │ │ │ ├── react │ │ │ │ ├── src │ │ │ │ │ ├── App.css │ │ │ │ │ ├── App.jsx │ │ │ │ │ └── index.jsx │ │ │ │ └── webpack.config.js │ │ │ ├── standardjs │ │ │ │ └── .eslintrc.js │ │ │ ├── vue │ │ │ │ ├── src │ │ │ │ │ ├── App.vue │ │ │ │ │ └── index.js │ │ │ │ └── webpack.config.js │ │ │ └── web │ │ │ │ ├── src │ │ │ │ └── index.js │ │ │ │ └── webpack.config.js │ │ │ └── utils.js │ ├── package.json │ └── test │ │ └── cli_test.js ├── dev-server │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── eslint │ ├── .npmignore │ ├── README.md │ ├── eslintrc.js │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── font-loader │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── html-loader │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── html-template │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ ├── template.ejs │ └── test │ │ └── middleware_test.js ├── image-loader │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── jest │ ├── .npmignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── file-mock.js │ │ ├── index.js │ │ ├── style-mock.js │ │ └── transformer.js │ └── test │ │ └── jest_test.js ├── karma │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── karma_test.js ├── library │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── library_test.js ├── migrate │ ├── .npmignore │ ├── README.md │ ├── bin │ │ └── migrate.js │ ├── package.json │ ├── test │ │ ├── fixtures │ │ │ ├── .neutrinorc.js │ │ │ └── .neutrinorc.js.txt │ │ └── migrate_test.js │ └── transforms │ │ └── middleware.js ├── mocha │ ├── .npmignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.js │ │ └── register.js │ └── test │ │ └── mocha_test.js ├── neutrino │ ├── .npmignore │ ├── Neutrino.js │ ├── README.md │ ├── bin │ │ └── neutrino.js │ ├── errors.js │ ├── extensions.js │ ├── handlers.js │ ├── index.js │ ├── package.json │ └── test │ │ ├── api_test.js │ │ ├── fixtures │ │ ├── middleware.js │ │ └── test-module │ │ │ ├── errorMiddleware.js │ │ │ ├── middleware.js │ │ │ └── node_modules │ │ │ └── alpha │ │ │ └── index.js │ │ └── package_test.js ├── node │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── node_test.js ├── preact │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── preact_test.js ├── react-components │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ ├── components_test.js │ │ └── src │ │ └── components │ │ └── Empty.jsx ├── react │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── react_test.js ├── standardjs │ ├── .npmignore │ ├── README.md │ ├── eslintrc.js │ ├── index.js │ ├── package.json │ └── test │ │ └── standardjs_test.js ├── start-server │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── style-loader │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── style-minify │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── middleware_test.js ├── vue │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ │ └── vue_test.js └── web │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── test │ └── web_test.js ├── renovate.json ├── scripts ├── build-docs.sh └── test-create-project-ci.sh ├── verdaccio.npm.yml ├── verdaccio.yarn.yml └── yarn.lock /.auto-changelog: -------------------------------------------------------------------------------- 1 | { 2 | "commitLimit": false, 3 | "releaseSummary": true, 4 | "remote": "upstream" 5 | } 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # ESLint only ignores the repo root node_modules by default. 2 | packages/**/node_modules/ 3 | 4 | # This file intentionally contains invalid syntax so results in a parse error. 5 | packages/neutrino/test/fixtures/test-module/errorMiddleware.js 6 | 7 | # By using --no-eslintrc in yarn lint, eslint no longer lints the nested 8 | # RC files. We then negate this ignore so they are still linted, but no longer 9 | # used as configuration by our development lint command. 10 | !packages/create-project/bin/commands/init/templates/*/.eslintrc.js 11 | 12 | # Ignore directories that may potentially have JS we don't need linted 13 | coverage 14 | docs 15 | build 16 | .nyc_output 17 | 18 | # Lint dotfiles 19 | !.*.js 20 | 21 | # Do not use prettier to re-format the changelog 22 | CHANGELOG.md 23 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('./packages/neutrino'); 2 | 3 | module.exports = neutrino().eslintrc(); 4 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of 9 | experience, nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject 41 | comments, commits, code, wiki edits, issues, and other contributions that are 42 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 43 | contributor for other behaviors that they deem inappropriate, threatening, 44 | offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project lead at eli@mozilla.com. All complaints will 59 | be reviewed and investigated and will result in a response that is deemed 60 | necessary and appropriate to the circumstances. The project team is obligated to 61 | maintain confidentiality with regard to the reporter of an incident. Further 62 | details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 71 | version 1.4, available at 72 | [https://www.contributor-covenant.org/version/1/4][version] 73 | 74 | [homepage]: https://www.contributor-covenant.org 75 | [version]: https://www.contributor-covenant.org/version/1/4/code-of-conduct 76 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Bug or issue? 2 | 3 | Please try to answer the following questions: 4 | 5 | - What version of Neutrino are you using? 6 | - Are you trying to use any presets? If so, which ones, and what versions? 7 | - Are you using the Yarn client or the npm client? What version? 8 | - What version of Node.js are you using? 9 | - What operating system are you using? 10 | - What did you do? 11 | - What did you expect to happen? 12 | - What actually happened, contrary to your expectations? 13 | 14 | ### Feature request or enhancement? 15 | 16 | Please describe your request in detail. Use the following questions as guidance: 17 | 18 | - What is the goal of the change? 19 | - What are the pros and cons of the change? 20 | - Could this dramatically improve the experience of our users? 21 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | Neutrino team members and contributors are here to help you! Should you need 4 | assistance or have questions in using Neutrino or its core presets, please 5 | consider asking on our Spectrum channel, Stack Overflow, or other channel rather 6 | than filing issues. We would prefer to keep our GitHub issues clear for bugs, 7 | feature requests, discussions, and relevant information related to its 8 | development. 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Check out Git repository 11 | uses: actions/checkout@v2 12 | 13 | - name: Install Node.js, NPM and Yarn 14 | uses: actions/setup-node@v2 15 | with: 16 | node-version: 16 17 | cache: 'yarn' 18 | 19 | - name: Install modules 20 | run: yarn install --prefer-offline --frozen-lockfile 21 | 22 | - name: Run validate:eslintrc 23 | run: yarn validate:eslintrc 24 | 25 | - name: Run lint 26 | run: yarn lint 27 | 28 | - name: Run prettier:check 29 | run: yarn prettier:check 30 | 31 | test: 32 | runs-on: ubuntu-latest 33 | 34 | strategy: 35 | matrix: 36 | node: ['12', '14', '16'] 37 | 38 | name: Test Node ${{ matrix.node }} 39 | 40 | steps: 41 | - name: Check out Git repository 42 | uses: actions/checkout@v2 43 | 44 | - name: Install Node.js, NPM and Yarn 45 | uses: actions/setup-node@v2 46 | with: 47 | node-version: ${{ matrix.node }} 48 | cache: 'yarn' 49 | 50 | - name: Install modules 51 | run: yarn install --prefer-offline --frozen-lockfile 52 | 53 | - name: Run unit tests 54 | run: yarn test 55 | 56 | - name: Create test project with yarn 57 | run: scripts/test-create-project-ci.sh 58 | env: 59 | CREATE_PROJECT_YARN: 'true' 60 | 61 | - name: Create test project with npm 62 | run: scripts/test-create-project-ci.sh 63 | env: 64 | CREATE_PROJECT_YARN: 'false' 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | lerna-debug.log 6 | 7 | # Build directories 8 | build 9 | lib 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | .nyc_output 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Dependency directories 28 | node_modules 29 | 30 | # But allow node_modules for test fixtures 31 | !packages/neutrino/test/fixtures/test-module/node_modules 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Project metadata 40 | .idea 41 | /.vscode 42 | 43 | # ESlint CLI cache 44 | .eslintcache 45 | -------------------------------------------------------------------------------- /.huskyrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | hooks: { 3 | 'pre-commit': 'lint-staged', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,jsx}': ['yarn lint'], 3 | '*.{css,html,js,jsx,json,md,yaml,yml}': ['yarn prettier:check'], 4 | }; 5 | -------------------------------------------------------------------------------- /.neutrinorc.js: -------------------------------------------------------------------------------- 1 | const airbnb = require('./packages/airbnb'); 2 | 3 | module.exports = { 4 | options: { 5 | root: __dirname, 6 | }, 7 | use: [ 8 | airbnb({ 9 | // See the package.json `lint` script for which files are linted. 10 | // Excludes are managed via `.eslintignore`. 11 | eslint: { 12 | baseConfig: { 13 | extends: ['plugin:prettier/recommended'], 14 | env: { 15 | browser: true, 16 | jest: true, 17 | mocha: true, 18 | node: true, 19 | }, 20 | rules: { 21 | 'prettier/prettier': [ 22 | 'error', 23 | { 24 | singleQuote: true, 25 | bracketSameLine: true, 26 | trailingComma: 'all', 27 | proseWrap: 'always', 28 | }, 29 | ], 30 | // Allow using console since most of the code in this repo isn't run in a browser. 31 | 'no-console': 'off', 32 | // Allowing shadowing variable that share the same context as the outer scope 33 | 'no-shadow': 'off', 34 | }, 35 | overrides: [ 36 | { 37 | files: [ 38 | 'packages/create-project/commands/init/templates/**', 39 | 'packages/create-project/commands/init/templates/*/.*.js', 40 | ], 41 | rules: { 42 | // The dependencies in create-project's templates are installed by 43 | // by create-project and so are expected to be missing from package.json. 44 | 'import/no-extraneous-dependencies': 'off', 45 | }, 46 | }, 47 | { 48 | files: [ 49 | 'packages/create-project/commands/init/templates/preact/**', 50 | ], 51 | settings: { 52 | react: { 53 | pragma: 'h', 54 | }, 55 | }, 56 | rules: { 57 | // With Preact the use of `class` is recommended over `className`, 58 | // so we have to add `class` to the ignore list, to prevent: 59 | // `Unknown property 'class' found, use 'className' instead` 60 | 'react/no-unknown-property': ['error', { ignore: ['class'] }], 61 | }, 62 | }, 63 | { 64 | files: ['packages/*/test/*'], 65 | rules: { 66 | // The tests need to do non-global require() to test the presets. 67 | 'global-require': 'off', 68 | // This rule doesn't handle devDependencies being defined 69 | // in the monorepo root package.json. 70 | 'import/no-extraneous-dependencies': 'off', 71 | }, 72 | }, 73 | ], 74 | }, 75 | }, 76 | }), 77 | (neutrino) => { 78 | neutrino.register('prettierrc', (neutrino) => { 79 | const handler = neutrino.outputHandlers.get('eslintrc'); 80 | const eslintConfig = handler(neutrino); 81 | 82 | return eslintConfig.rules['prettier/prettier'][1]; 83 | }); 84 | }, 85 | ], 86 | }; 87 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('./packages/neutrino'); 2 | 3 | module.exports = neutrino().prettierrc(); 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | ### Create and build modern JavaScript applications with zero initial configuration 4 | 5 | #### Neutrino combines the power of webpack with the simplicity of presets. 6 | 7 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 8 | [![CI Status][ci-image]][ci-url] [![Netlify Status][netlify-image]][netlify-url] 9 | 10 | [https://github.com/neutrinojs/neutrino](https://github.com/neutrinojs/neutrino) 11 | 12 | --- 13 | 14 | Neutrino is a companion tool which lets you build web and Node.js applications 15 | with shared presets or configurations. It intends to make the process of 16 | initializing and building projects much simpler by providing minimal development 17 | dependencies. 18 | 19 | Neutrino uses webpack to build both web and Node.js projects by providing 20 | complete build presets which can be shared across targets and projects. You can 21 | use Neutrino base presets to get started building a variety of projects, create 22 | your own presets by extending the Neutrino core ones to be shared across your 23 | own projects or even by the community. Presets can even be manipulated on a 24 | project-by-project basis to handle almost any build situation your preset 25 | doesn't cover. 26 | 27 | ## Documentation 28 | 29 | See the [Neutrino docs](https://neutrinojs.org/) for details on installation, 30 | getting started, usage, and customizing. 31 | 32 | ### Contributing 33 | 34 | Thank you for wanting to help out with Neutrino! We are very happy that you want 35 | to contribute, and have put together this guide to help you get started. We want 36 | to do our best to help you make successful contributions and be part of our 37 | community. 38 | 39 | - [Contributing to Neutrino](https://neutrinojs.org/contributing/) 40 | - [Participation Guidelines](https://neutrinojs.org/contributing/code-of-conduct/) 41 | 42 | [npm-image]: https://img.shields.io/npm/v/neutrino.svg 43 | [npm-downloads]: https://img.shields.io/npm/dt/neutrino.svg 44 | [npm-url]: https://www.npmjs.com/package/neutrino 45 | [ci-image]: 46 | https://github.com/neutrinojs/neutrino/actions/workflows/ci.yml/badge.svg 47 | [ci-url]: https://github.com/neutrinojs/neutrino/actions/workflows/ci.yml 48 | [netlify-image]: 49 | https://api.netlify.com/api/v1/badges/faef6419-2d67-488a-95a8-998e1ad3e40f/deploy-status 50 | [netlify-url]: https://app.netlify.com/sites/neutrinojs/deploys 51 | -------------------------------------------------------------------------------- /docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neutrinojs/neutrino/f9d476446983684225545159f58bbed2a93ca824/docs/assets/logo.png -------------------------------------------------------------------------------- /docs/contributing/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project lead at eli@mozilla.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://www.contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | [version]: https://www.contributor-covenant.org/version/1/4/code-of-conduct 75 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Create and build modern JavaScript applications with zero initial configuration

4 |

Neutrino combines the power of webpack with the simplicity of presets.

5 | 6 | [![NPM version][npm-image]][npm-url] 7 | [![NPM downloads][npm-downloads]][npm-url] 8 | [![CI Status][ci-image]][ci-url] 9 | [![Netlify Status][netlify-image]][netlify-url] 10 | 11 | [https://github.com/neutrinojs/neutrino](https://github.com/neutrinojs/neutrino) 12 | 13 | --- 14 | 15 | Neutrino is a companion tool which lets you build web and Node.js applications with shared presets or configurations. 16 | It intends to make the process of initializing and building projects much simpler by providing minimal development 17 | dependencies. 18 | 19 | Neutrino uses webpack to build both web and Node.js projects by providing complete build presets which can be shared 20 | across targets and projects. You can use Neutrino base presets to get started building a variety of projects, create 21 | your own presets by extending the Neutrino core ones to be shared across your own projects or even by the community. 22 | Presets can even be manipulated on a project-by-project basis to handle almost any build situation your preset doesn't 23 | cover. 24 | 25 | [npm-image]: https://img.shields.io/npm/v/neutrino.svg 26 | [npm-downloads]: https://img.shields.io/npm/dt/neutrino.svg 27 | [npm-url]: https://www.npmjs.com/package/neutrino 28 | [ci-image]: https://github.com/neutrinojs/neutrino/actions/workflows/ci.yml/badge.svg 29 | [ci-url]: https://github.com/neutrinojs/neutrino/actions/workflows/ci.yml 30 | [netlify-image]: https://api.netlify.com/api/v1/badges/faef6419-2d67-488a-95a8-998e1ad3e40f/deploy-status 31 | [netlify-url]: https://app.netlify.com/sites/neutrinojs/deploys 32 | -------------------------------------------------------------------------------- /docs/installation/create-new-project.md: -------------------------------------------------------------------------------- 1 | ../../packages/create-project/README.md -------------------------------------------------------------------------------- /docs/installation/index.md: -------------------------------------------------------------------------------- 1 | # Installing Neutrino 2 | 3 | ## Requirements 4 | 5 | Installing Neutrino requires Node.js 10+, and either [Yarn](https://yarnpkg.com/en/docs/install) or 6 | npm. At a minimum, you will be installing Neutrino and Neutrino middleware, such as `@neutrinojs/react`. 7 | 8 | ## Create New Project 9 | 10 | The fastest way to get started is by using the [`@neutrinojs/create-project`](./create-new-project.md) scaffolding tool. 11 | If you don’t want to use the CLI helper, proceed below for manual installation instructions. 12 | 13 | ## Yarn Installation 14 | 15 | Run the following command inside your project directory. Substitute `MIDDLEWARE` with the name of the middleware 16 | you wish to install. 17 | 18 | ```bash 19 | yarn add --dev neutrino MIDDLEWARE 20 | ``` 21 | 22 | For example, if you wanted to build your project using Neutrino's React preset: 23 | 24 | ```bash 25 | yarn add --dev neutrino @neutrinojs/react 26 | ``` 27 | 28 | ## npm Installation 29 | 30 | Run the following command inside your project directory. Substitute `MIDDLEWARE` with the name of the middleware 31 | you wish to install. 32 | 33 | ```bash 34 | npm install --save-dev neutrino MIDDLEWARE 35 | ``` 36 | 37 | For example, if you wanted to build your project using Neutrino's React preset: 38 | 39 | ```bash 40 | npm install --save-dev neutrino @neutrinojs/react 41 | ``` 42 | 43 | ## Getting started 44 | 45 | Please continue through the documentation for instructions on Neutrino usage and default project layout. 46 | -------------------------------------------------------------------------------- /docs/learning-resources.md: -------------------------------------------------------------------------------- 1 | # Learning Resources 2 | 3 | Here we keep a listing of external learning resources related to Neutrino and its presets, things like blog posts, 4 | tutorials, screencasts, videos, starter repos, and more. If you would like to submit a resource for the benefit of the 5 | community, file an issue or submit a pull request. 6 | 7 | ## Blog Posts & Tutorials 8 | 9 | #### v6, v7 10 | 11 | * [Neutrino - Create modern JavaScript applications with minimal configuration - Interview with Eli Perelman](https://survivejs.com/blog/neutrino-interview/) by [@survivejs](https://twitter.com/survivejs) 12 | 13 | #### v5 14 | 15 | * [Code Splitting for React Router with webpack and HMR](https://hackernoon.com/code-splitting-for-react-router-with-webpack-and-hmr-bb509968e86f) by [@hassanhelfi](https://twitter.com/hassanhelfi) 16 | 17 | #### v4 18 | 19 | * [Modern JavaScript Apps with Neutrino](https://davidwalsh.name/neutrino) by [@eliperelman](https://twitter.com/eliperelman) 20 | * [Using Neutrino to jump-start modern JavaScript development](https://hacks.mozilla.org/2017/02/using-neutrino-for-modern-javascript-development/) by [@eliperelman](https://twitter.com/eliperelman) 21 | * [Custom Neutrino Linting](https://davidwalsh.name/neutrino-linting) by [@davidwalshblog](https://twitter.com/davidwalshblog) 22 | 23 | ## Screencasts & Videos 24 | 25 | #### v5 26 | 27 | * [Bootstrap a Zero Configuration React App with Neutrino](https://egghead.io/lessons/react-bootstrap-a-zero-configuration-react-app-with-neutrino) by [@markshust](https://twitter.com/markshust) 28 | * [Empower and Simplify JavaScript Development](https://www.youtube.com/watch?v=fz5jMdmKmRI) by [@eliperelman](https://twitter.com/eliperelman) at [@nebraskajs](https://nebraskajs.com) 29 | 30 | ## Third Party Presets and Middleware 31 | 32 | Other presets and middleware that can be taken as examples to learn from: 33 | 34 | * [Preset for Zoho Sites Template development](https://gitlab.com/ringods/neutrino-preset-zoho-sites-template) 35 | -------------------------------------------------------------------------------- /docs/migrate.md: -------------------------------------------------------------------------------- 1 | ../packages/migrate/README.md -------------------------------------------------------------------------------- /docs/packages/airbnb-base.md: -------------------------------------------------------------------------------- 1 | ../../packages/airbnb-base/README.md -------------------------------------------------------------------------------- /docs/packages/airbnb.md: -------------------------------------------------------------------------------- 1 | ../../packages/airbnb/README.md -------------------------------------------------------------------------------- /docs/packages/banner.md: -------------------------------------------------------------------------------- 1 | ../../packages/banner/README.md -------------------------------------------------------------------------------- /docs/packages/clean.md: -------------------------------------------------------------------------------- 1 | ../../packages/clean/README.md -------------------------------------------------------------------------------- /docs/packages/compile-loader.md: -------------------------------------------------------------------------------- 1 | ../../packages/compile-loader/README.md -------------------------------------------------------------------------------- /docs/packages/copy.md: -------------------------------------------------------------------------------- 1 | ../../packages/copy/README.md -------------------------------------------------------------------------------- /docs/packages/dev-server.md: -------------------------------------------------------------------------------- 1 | ../../packages/dev-server/README.md -------------------------------------------------------------------------------- /docs/packages/eslint.md: -------------------------------------------------------------------------------- 1 | ../../packages/eslint/README.md -------------------------------------------------------------------------------- /docs/packages/font-loader.md: -------------------------------------------------------------------------------- 1 | ../../packages/font-loader/README.md -------------------------------------------------------------------------------- /docs/packages/html-loader.md: -------------------------------------------------------------------------------- 1 | ../../packages/html-loader/README.md -------------------------------------------------------------------------------- /docs/packages/html-template.md: -------------------------------------------------------------------------------- 1 | ../../packages/html-template/README.md -------------------------------------------------------------------------------- /docs/packages/image-loader.md: -------------------------------------------------------------------------------- 1 | ../../packages/image-loader/README.md -------------------------------------------------------------------------------- /docs/packages/jest.md: -------------------------------------------------------------------------------- 1 | ../../packages/jest/README.md -------------------------------------------------------------------------------- /docs/packages/karma.md: -------------------------------------------------------------------------------- 1 | ../../packages/karma/README.md -------------------------------------------------------------------------------- /docs/packages/library.md: -------------------------------------------------------------------------------- 1 | ../../packages/library/README.md -------------------------------------------------------------------------------- /docs/packages/mocha.md: -------------------------------------------------------------------------------- 1 | ../../packages/mocha/README.md -------------------------------------------------------------------------------- /docs/packages/node.md: -------------------------------------------------------------------------------- 1 | ../../packages/node/README.md -------------------------------------------------------------------------------- /docs/packages/preact.md: -------------------------------------------------------------------------------- 1 | ../../packages/preact/README.md -------------------------------------------------------------------------------- /docs/packages/react-components.md: -------------------------------------------------------------------------------- 1 | ../../packages/react-components/README.md -------------------------------------------------------------------------------- /docs/packages/react.md: -------------------------------------------------------------------------------- 1 | ../../packages/react/README.md -------------------------------------------------------------------------------- /docs/packages/standardjs.md: -------------------------------------------------------------------------------- 1 | ../../packages/standardjs/README.md -------------------------------------------------------------------------------- /docs/packages/start-server.md: -------------------------------------------------------------------------------- 1 | ../../packages/start-server/README.md -------------------------------------------------------------------------------- /docs/packages/style-loader.md: -------------------------------------------------------------------------------- 1 | ../../packages/style-loader/README.md -------------------------------------------------------------------------------- /docs/packages/style-minify.md: -------------------------------------------------------------------------------- 1 | ../../packages/style-minify/README.md -------------------------------------------------------------------------------- /docs/packages/vue.md: -------------------------------------------------------------------------------- 1 | ../../packages/vue/README.md -------------------------------------------------------------------------------- /docs/packages/web.md: -------------------------------------------------------------------------------- 1 | ../../packages/web/README.md -------------------------------------------------------------------------------- /docs/presets.md: -------------------------------------------------------------------------------- 1 | # What are presets? 2 | 3 | A preset is a Neutrino-compatible configuration capable of building, modifying 4 | the build process, or interacting with a project as a result of building. 5 | Neutrino provides a few core presets to quickly get started building some popular project 6 | types, but anyone can inherit, extend, and modify these presets and tailor them to their project, 7 | team, or company preferences. You can even create your own presets from scratch. 8 | 9 | If you are familiar with Babel presets, Neutrino presets work similarly. For example, 10 | given the Babel preset `@babel/preset-react`, you can compile React code with JSX 11 | to vanilla JavaScript calls. Neutrino adopts this same concept by adapting webpack into 12 | a tool that understands configurations-as-packages, i.e. presets. Many more aspects of 13 | development surround building a complete React project, for which webpack is commonly used. 14 | By encapsulating the common needs of a project type into a preset, Neutrino allows you to 15 | avoid the upfront cost of configuring and instead focus on project development. 16 | 17 | Not every project is the same, and oftentimes small tweaks need to be made to the build 18 | configuration in order to meet this need. Fortunately Neutrino presets can be modified and 19 | extended directly from the project you are building. No need to be locked in to a particular 20 | pattern, and no escape hatches that force you into maintaining the entire configuration should 21 | you need to make changes. 22 | 23 | Presets can be easily distributed by publishing them to npm or GitHub and installing them 24 | in your project. This also allows others to discover and build projects based on your own 25 | presets. 26 | -------------------------------------------------------------------------------- /docs/project-layout.md: -------------------------------------------------------------------------------- 1 | # Project Layout 2 | 3 | Out of the box, Neutrino presets expect a project to have a particular structure to make the 4 | development process for new projects as quick as possible. This is broken up into four directories: 5 | 6 | - Source code 7 | - Static assets 8 | - Build assets 9 | - Testing 10 | 11 | Each of these directories is set up via convention by a Neutrino preset, but each can be customized as 12 | desired by overriding the preset's configuration or using a different preset. See 13 | [Custom Configuration](./customization.md) for detailed instructions. 14 | 15 | ## Source Code 16 | 17 | By default, Neutrino presets expect all project source code to live in a directory named `src` in the 18 | root of the project. This includes compiled and imported JavaScript files, CSS stylesheets, images, and any other assets 19 | that would be available to your compiled project. 20 | 21 | When running your project or creating a build bundle, a preset will look for this `src` directory for 22 | the main entry points of your application and use this as the relative location for finding other assets 23 | necessary for creating your builds. 24 | 25 | ## Build Assets 26 | 27 | When creating a build bundle, a preset will put the compiled assets, including any generated 28 | JavaScript files, into a directory named `build` by default. 29 | 30 | Normally most projects will exclude checking in this build directory to source control. 31 | Be sure to add this directory to your project's `.gitignore`, `.hgignore`, or similar file. 32 | 33 | ## Testing 34 | 35 | Neutrino presets by default expect all tests to be located in a directory named `test`. In order to make the 36 | separation between tests and test fixtures or harnesses easier to differentiate, Neutrino presets also 37 | usually look for test files ending in `_test.js` or `.test.js`. See your specific test preset for more 38 | detailed information about running tests and other conventions. 39 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs-material>=7,<8 2 | -------------------------------------------------------------------------------- /docs/runtime.txt: -------------------------------------------------------------------------------- 1 | 3.8 2 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "9.5.0", 3 | "npmClient": "yarn", 4 | "registry": "https://registry.npmjs.org/", 5 | "useWorkspaces": true, 6 | "command": { 7 | "version": { 8 | "exact": true, 9 | "forcePublish": "*", 10 | "gitRemote": "upstream", 11 | "gitTagVersion": false, 12 | "push": false 13 | }, 14 | "publish": { 15 | "exact": true, 16 | "forcePublish": "*", 17 | "gitRemote": "upstream", 18 | "gitTagVersion": false, 19 | "push": false 20 | } 21 | }, 22 | "packages": ["packages/*"] 23 | } 24 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | docs_dir: 'docs' 2 | site_dir: 'build' 3 | strict: true 4 | 5 | site_name: 'Neutrino' 6 | site_description: 7 | 'Create and build modern JavaScript applications with zero initial 8 | configuration' 9 | repo_name: 'neutrinojs/neutrino' 10 | repo_url: 'https://github.com/neutrinojs/neutrino' 11 | 12 | # https://squidfunk.github.io/mkdocs-material/getting-started/#configuration 13 | theme: 14 | name: 'material' 15 | palette: 16 | primary: 'teal' 17 | accent: 'teal' 18 | icon: 19 | repo: 'fontawesome/brands/github' 20 | 21 | # http://www.mkdocs.org/user-guide/writing-your-docs/#configure-pages-and-navigation 22 | nav: 23 | - Introduction: './index.md' 24 | - Getting Started: 25 | - Installation: './installation/index.md' 26 | - Create new project: './installation/create-new-project.md' 27 | - Usage: './usage.md' 28 | - Project Layout: './project-layout.md' 29 | - Customization: './customization.md' 30 | - Configuration: './webpack-chain.md' 31 | - Migration Guide: './migration-guide.md' 32 | - Migration Tool: './migrate.md' 33 | - Presets: 34 | - What are presets?: './presets.md' 35 | - Web Projects: 36 | - React: './packages/react.md' 37 | - Preact: './packages/preact.md' 38 | - Vue: './packages/vue.md' 39 | - Web: './packages/web.md' 40 | - Node.js: './packages/node.md' 41 | - React Components: './packages/react-components.md' 42 | - Libraries: './packages/library.md' 43 | - Linting: 44 | - Airbnb: './packages/airbnb.md' 45 | - StandardJS: './packages/standardjs.md' 46 | - Airbnb Base: './packages/airbnb-base.md' 47 | - Testing: 48 | - Jest: './packages/jest.md' 49 | - Karma: './packages/karma.md' 50 | - Mocha: './packages/mocha.md' 51 | - Middleware: 52 | - What is middleware?: './middleware.md' 53 | - banner: './packages/banner.md' 54 | - clean: './packages/clean.md' 55 | - compile-loader: './packages/compile-loader.md' 56 | - copy: './packages/copy.md' 57 | - dev-server: './packages/dev-server.md' 58 | - eslint: './packages/eslint.md' 59 | - font-loader: './packages/font-loader.md' 60 | - html-loader: './packages/html-loader.md' 61 | - html-template: './packages/html-template.md' 62 | - image-loader: './packages/image-loader.md' 63 | - start-server: './packages/start-server.md' 64 | - style-loader: './packages/style-loader.md' 65 | - style-minify: './packages/style-minify.md' 66 | - API: './api.md' 67 | - Creating Presets: './creating-presets.md' 68 | - Previous Versions: 69 | - v8 Documentation: 'https://release-v8.neutrinojs.org/' 70 | - v7 Documentation: 'https://release-v7.neutrinojs.org/' 71 | - v6 Documentation: 'https://github.com/neutrinojs/neutrino/tree/release/v6/docs' 72 | - v5 Documentation: 'https://github.com/neutrinojs/neutrino/tree/release/v5/docs' 73 | - v4 Documentation: 'https://github.com/neutrinojs/neutrino/tree/release/v4/docs' 74 | - FAQ: './faq.md' 75 | - Learning Resources: './learning-resources.md' 76 | - Contributing: 77 | - Overview: './contributing/index.md' 78 | - Development Process: './contributing/development.md' 79 | - Code of Conduct: './contributing/code-of-conduct.md' 80 | 81 | # https://squidfunk.github.io/mkdocs-material/getting-started/#extensions 82 | markdown_extensions: 83 | - admonition 84 | - codehilite: 85 | guess_lang: false 86 | - toc: 87 | permalink: true 88 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | # Using a non-root base directory/requirements file to prevent 3 | # Netlify from finding package.json and trying to install that: 4 | # https://github.com/netlify/build-image/issues/141 5 | base = "docs" 6 | publish = "build" 7 | command = "../scripts/build-docs.sh" 8 | 9 | # Redirect domain aliases to the primary domain. 10 | 11 | [[redirects]] 12 | from = "https://neutrino.js.org/*" 13 | to = "https://neutrinojs.org/:splat" 14 | force = true 15 | 16 | [[redirects]] 17 | from = "https://neutrinojs.netlify.com/*" 18 | to = "https://neutrinojs.org/:splat" 19 | force = true 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neutrino", 3 | "private": true, 4 | "author": "Eli Perelman ", 5 | "license": "MPL-2.0", 6 | "homepage": "https://neutrinojs.org", 7 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 8 | "repository": "neutrinojs/neutrino", 9 | "engines": { 10 | "node": ">=12", 11 | "npm": ">=6.13.0", 12 | "yarn": ">=1.22.0" 13 | }, 14 | "workspaces": [ 15 | "packages/*" 16 | ], 17 | "scripts": { 18 | "changelog": "auto-changelog", 19 | "changelog:unreleased": "auto-changelog --package lerna.json", 20 | "docs:bootstrap": "pip install -r docs/requirements.txt", 21 | "docs:serve": "mkdocs serve", 22 | "link:all": "lerna exec yarn link", 23 | "lint": "eslint --no-eslintrc --config ./.eslintrc.js --cache --report-unused-disable-directives --format codeframe --ext js,jsx .", 24 | "prettier:check": "prettier --ignore-path .eslintignore --check \"**/*.{css,html,js,jsx,json,md,yaml,yml}\"", 25 | "prettier:fix": "prettier --ignore-path .eslintignore --write \"**/*.{css,html,js,jsx,json,md,yaml,yml}\"", 26 | "print-version": "node -p \"'v' +require('./lerna.json').version\"", 27 | "release:prepare": "lerna version && prettier --write lerna.json && yarn changelog:unreleased", 28 | "release:commit": "git commit --all --message $(yarn -s print-version) --edit", 29 | "release:tag": "git tag $(yarn -s print-version) && git push upstream $(yarn -s print-version)", 30 | "release:publish": "lerna publish from-package", 31 | "release:publish-next": "yarn release:publish --dist-tag next", 32 | "release:ci": "lerna publish preminor --registry http://localhost:4873 --no-git-reset --yes", 33 | "test": "ava --fail-fast packages/*/test \"!packages/create-project/test\"", 34 | "test:create-project": "ava --verbose packages/create-project/test", 35 | "validate:eslintrc:root": "eslint --no-eslintrc --print-config ./.eslintrc.js > /dev/null", 36 | "validate:eslintrc:eslint": "eslint --no-eslintrc --print-config ./packages/eslint/eslintrc.js > /dev/null", 37 | "validate:eslintrc:airbnb": "eslint --no-eslintrc --print-config ./packages/airbnb/eslintrc.js > /dev/null", 38 | "validate:eslintrc:airbnb-base": "eslint --no-eslintrc --print-config ./packages/airbnb-base/eslintrc.js > /dev/null", 39 | "validate:eslintrc:standardjs": "eslint --no-eslintrc --print-config ./packages/standardjs/eslintrc.js > /dev/null", 40 | "validate:eslintrc": "yarn validate:eslintrc:eslint && yarn validate:eslintrc:airbnb-base && yarn validate:eslintrc:airbnb && yarn validate:eslintrc:standardjs && yarn validate:eslintrc:root" 41 | }, 42 | "devDependencies": { 43 | "auto-changelog": "^2.2.1", 44 | "ava": "^1.4.1", 45 | "eslint": "^7.16.0", 46 | "eslint-config-prettier": "^8.0.0", 47 | "eslint-plugin-prettier": "^4.0.0", 48 | "husky": "^4.3.6", 49 | "jest": "^26.6.3", 50 | "karma": "^5.2.3", 51 | "karma-cli": "^2.0.0", 52 | "lerna": "^3.22.1", 53 | "lint-staged": "^10.5.3", 54 | "mocha": "^8.2.1", 55 | "prettier": "^2.2.1", 56 | "verdaccio": "^5.1.0", 57 | "verdaccio-memory": "^10.0.0", 58 | "webpack": "^4.44.2", 59 | "webpack-cli": "^3.3.12", 60 | "webpack-dev-server": "^3.11.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/airbnb-base/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | eslintrc.js 3 | -------------------------------------------------------------------------------- /packages/airbnb-base/eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('../neutrino'); 2 | const middleware = require('.'); 3 | 4 | module.exports = neutrino({ 5 | use: middleware(), 6 | options: { 7 | root: __dirname, 8 | }, 9 | }).eslintrc(); 10 | -------------------------------------------------------------------------------- /packages/airbnb-base/index.js: -------------------------------------------------------------------------------- 1 | const lint = require('@neutrinojs/eslint'); 2 | const { 3 | rules: airbnbBaseStyle, 4 | } = require('eslint-config-airbnb-base/rules/style'); 5 | const { 6 | rules: airbnbBaseBestPractices, 7 | } = require('eslint-config-airbnb-base/rules/best-practices'); 8 | 9 | module.exports = 10 | ({ eslint = {}, ...opts } = {}) => 11 | (neutrino) => { 12 | const baseConfig = eslint.baseConfig || {}; 13 | neutrino.use( 14 | lint({ 15 | ...opts, 16 | eslint: { 17 | ...eslint, 18 | baseConfig: { 19 | ...baseConfig, 20 | extends: [ 21 | require.resolve('eslint-config-airbnb-base'), 22 | ...(baseConfig.extends || []), 23 | ], 24 | rules: { 25 | // Disable rules for which there are eslint-plugin-babel replacements: 26 | // https://github.com/babel/eslint-plugin-babel#rules 27 | 'new-cap': 'off', 28 | 'no-invalid-this': 'off', 29 | 'object-curly-spacing': 'off', 30 | semi: 'off', 31 | 'no-unused-expressions': 'off', 32 | // Ensure the replacement rules use the options set by airbnb-base rather than ESLint defaults. 33 | 'babel/new-cap': airbnbBaseStyle['new-cap'], 34 | 'babel/no-invalid-this': 35 | airbnbBaseBestPractices['no-invalid-this'], 36 | 'babel/object-curly-spacing': 37 | airbnbBaseStyle['object-curly-spacing'], 38 | 'babel/semi': airbnbBaseStyle.semi, 39 | 'babel/no-unused-expressions': 40 | airbnbBaseBestPractices['no-unused-expressions'], 41 | ...baseConfig.rules, 42 | }, 43 | }, 44 | }, 45 | }), 46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /packages/airbnb-base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/airbnb-base", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for adding Airbnb's base JS ESLint config, following the Airbnb styleguide", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "airbnb", 10 | "eslint" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/airbnb-base" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "@neutrinojs/eslint": "9.5.0", 31 | "eslint-config-airbnb-base": "^14.2.1", 32 | "eslint-plugin-import": "^2.22.1" 33 | }, 34 | "peerDependencies": { 35 | "eslint": "^6.0.0 || ^7.0.0", 36 | "neutrino": "^9.0.0", 37 | "webpack": "^4.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/airbnb/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | eslintrc.js 3 | -------------------------------------------------------------------------------- /packages/airbnb/eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('../neutrino'); 2 | const middleware = require('.'); 3 | 4 | module.exports = neutrino({ 5 | use: middleware(), 6 | options: { 7 | root: __dirname, 8 | }, 9 | }).eslintrc(); 10 | -------------------------------------------------------------------------------- /packages/airbnb/index.js: -------------------------------------------------------------------------------- 1 | const lint = require('@neutrinojs/eslint'); 2 | const { 3 | rules: airbnbBaseStyle, 4 | } = require('eslint-config-airbnb-base/rules/style'); 5 | const { 6 | rules: airbnbBaseBestPractices, 7 | } = require('eslint-config-airbnb-base/rules/best-practices'); 8 | 9 | module.exports = 10 | ({ eslint = {}, ...opts } = {}) => 11 | (neutrino) => { 12 | const baseConfig = eslint.baseConfig || {}; 13 | neutrino.use( 14 | lint({ 15 | ...opts, 16 | eslint: { 17 | ...eslint, 18 | baseConfig: { 19 | ...baseConfig, 20 | extends: [ 21 | require.resolve('eslint-config-airbnb'), 22 | require.resolve('eslint-config-airbnb/hooks'), 23 | ...(baseConfig.extends || []), 24 | ], 25 | rules: { 26 | // Override AirBnB's configuration of 'always', since they only set that value due to 27 | // babel-preset-airbnb not supporting class properties, whereas @neutrinojs/react does. 28 | 'react/state-in-constructor': ['error', 'never'], 29 | // Disable rules for which there are eslint-plugin-babel replacements: 30 | // https://github.com/babel/eslint-plugin-babel#rules 31 | 'new-cap': 'off', 32 | 'no-invalid-this': 'off', 33 | 'object-curly-spacing': 'off', 34 | semi: 'off', 35 | 'no-unused-expressions': 'off', 36 | // Ensure the replacement rules use the options set by airbnb rather than ESLint defaults. 37 | 'babel/new-cap': airbnbBaseStyle['new-cap'], 38 | 'babel/no-invalid-this': 39 | airbnbBaseBestPractices['no-invalid-this'], 40 | 'babel/object-curly-spacing': 41 | airbnbBaseStyle['object-curly-spacing'], 42 | 'babel/semi': airbnbBaseStyle.semi, 43 | 'babel/no-unused-expressions': 44 | airbnbBaseBestPractices['no-unused-expressions'], 45 | ...baseConfig.rules, 46 | }, 47 | }, 48 | }, 49 | }), 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /packages/airbnb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/airbnb", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for adding Airbnb's JS ESLint config for React, following the Airbnb styleguide", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "airbnb", 10 | "eslint" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/airbnb" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "@neutrinojs/eslint": "9.5.0", 31 | "eslint-config-airbnb": "^18.2.1", 32 | "eslint-config-airbnb-base": "^14.2.1", 33 | "eslint-plugin-import": "^2.22.1", 34 | "eslint-plugin-jsx-a11y": "^6.4.1", 35 | "eslint-plugin-react": "^7.21.5", 36 | "eslint-plugin-react-hooks": "^4.2.0" 37 | }, 38 | "peerDependencies": { 39 | "eslint": "^6.0.0 || ^7.0.0", 40 | "neutrino": "^9.0.0", 41 | "webpack": "^4.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/banner/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/banner/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Banner Middleware 2 | 3 | `@neutrinojs/banner` is Neutrino middleware for injecting string content into 4 | source code files. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | 15 | ## Installation 16 | 17 | `@neutrinojs/banner` can be installed via the Yarn or npm clients. 18 | 19 | #### Yarn 20 | 21 | ```bash 22 | ❯ yarn add --dev @neutrinojs/banner 23 | ``` 24 | 25 | #### npm 26 | 27 | ```bash 28 | ❯ npm install --save-dev @neutrinojs/banner 29 | ``` 30 | 31 | ## Usage 32 | 33 | `@neutrinojs/banner` can be consumed from the Neutrino API, middleware, or 34 | presets. Require this package and plug it into Neutrino: 35 | 36 | ```js 37 | const banner = require('@neutrinojs/banner'); 38 | 39 | // Use with default options 40 | neutrino.use(banner()); 41 | 42 | // Also accepts options for webpack's BannerPlugin 43 | // https://webpack.js.org/plugins/banner-plugin/ 44 | 45 | // Usage shows the default values of this middleware: 46 | neutrino.use( 47 | banner({ 48 | banner: `require('source-map-support').install();`, 49 | test: neutrino.regexFromExtensions(), 50 | raw: true, 51 | entryOnly: true, 52 | // Override pluginId to add an additional banner plugin instance 53 | pluginId: 'banner', 54 | }), 55 | ); 56 | ``` 57 | 58 | ```js 59 | // Using in .neutrinorc.js 60 | const banner = require('@neutrinojs/banner'); 61 | 62 | // Use with default options 63 | module.exports = { 64 | use: [banner()], 65 | }; 66 | 67 | // Also accepts options for webpack's BannerPlugin 68 | // https://webpack.js.org/plugins/banner-plugin/ 69 | 70 | // Usage shows the default values of this middleware: 71 | module.exports = { 72 | use: [ 73 | banner({ 74 | banner: `require('source-map-support').install();`, 75 | test: neutrino.regexFromExtensions(), 76 | raw: true, 77 | entryOnly: true, 78 | // Override pluginId to add an additional banner plugin instance 79 | pluginId: 'banner', 80 | }), 81 | ], 82 | }; 83 | ``` 84 | 85 | ## Customization 86 | 87 | `@neutrinojs/banner` creates some conventions to make overriding the 88 | configuration easier once you are ready to make changes. 89 | 90 | ### Plugins 91 | 92 | The following is a list of plugins and their identifiers which can be 93 | overridden: 94 | 95 | | Name | Description | NODE_ENV | 96 | | -------- | ---------------------------------------------------- | -------- | 97 | | `banner` | Injects string content into application source code. | all | 98 | 99 | ## Contributing 100 | 101 | This middleware is part of the 102 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 103 | containing all resources for developing Neutrino and its core presets and 104 | middleware. Follow the 105 | [contributing guide](https://neutrinojs.org/contributing/) for details. 106 | 107 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/banner.svg 108 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/banner.svg 109 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/banner 110 | -------------------------------------------------------------------------------- /packages/banner/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | ({ pluginId = 'banner', ...options } = {}) => 3 | (neutrino) => { 4 | neutrino.config 5 | .plugin(pluginId) 6 | .use(require.resolve('webpack/lib/BannerPlugin'), [ 7 | { 8 | banner: "require('source-map-support').install();", 9 | test: neutrino.regexFromExtensions(), 10 | raw: true, 11 | entryOnly: true, 12 | ...options, 13 | }, 14 | ]); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/banner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/banner", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for injecting a banner into bundled files", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "banner" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/banner" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "peerDependencies": { 29 | "neutrino": "^9.0.0", 30 | "webpack": "^4.0.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/banner/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { raw: false, entryOnly: false }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/clean/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/clean/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Clean Middleware 2 | 3 | `@neutrinojs/clean` is Neutrino middleware for removing or cleaning build 4 | directories. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | By default, this plugin will remove all files inside webpack's `output.path` 9 | directory, as well as all unused webpack assets after every successful rebuild. 10 | 11 | ## Requirements 12 | 13 | - Node.js 10+ 14 | - Yarn v1.2.1+, or npm v5.4+ 15 | - Neutrino 9 16 | - webpack 4 17 | 18 | ## Installation 19 | 20 | `@neutrinojs/clean` can be installed via the Yarn or npm clients. 21 | 22 | #### Yarn 23 | 24 | ```bash 25 | ❯ yarn add --dev @neutrinojs/clean 26 | ``` 27 | 28 | #### npm 29 | 30 | ```bash 31 | ❯ npm install --save-dev @neutrinojs/clean 32 | ``` 33 | 34 | ## Usage 35 | 36 | `@neutrinojs/clean` can be consumed from the Neutrino API, middleware, or 37 | presets. Require this package and plug it into Neutrino: 38 | 39 | ```js 40 | const clean = require('@neutrinojs/clean'); 41 | 42 | // Use with default options 43 | neutrino.use(clean()); 44 | 45 | // Usage shows the default values of this middleware: 46 | neutrino.use( 47 | clean({ 48 | verbose: neutrino.options.debug, 49 | // Override pluginId to add an additional clean plugin instance 50 | pluginId: 'clean', 51 | }), 52 | ); 53 | ``` 54 | 55 | ```js 56 | // Using in .neutrinorc.js 57 | const clean = require('@neutrinojs/clean'); 58 | 59 | // Use with default options 60 | module.exports = { 61 | use: [clean()], 62 | }; 63 | 64 | // Usage shows the default values of this middleware: 65 | module.exports = { 66 | use: [ 67 | clean({ 68 | verbose: neutrino.options.debug, 69 | // Override pluginId to add an additional banner plugin instance 70 | pluginId: 'clean', 71 | }), 72 | ], 73 | }; 74 | ``` 75 | 76 | Additional options can be specified to control the behavior of the underlying 77 | `clean-webpack-plugin`. See 78 | [`CleanWebpackPlugin`'s documentation](https://github.com/johnagan/clean-webpack-plugin) 79 | for available options. 80 | 81 | ## Clean external directories 82 | 83 | Pass the `dangerouslyAllowCleanPatternsOutsideProject: true` option to remove 84 | directories outside of the project root. This is disabled by default to prevent 85 | deletion of unintended directories. 86 | 87 | ```js 88 | module.exports = { 89 | use: [ 90 | clean({ 91 | dangerouslyAllowCleanPatternsOutsideProject: true, 92 | }), 93 | ], 94 | }; 95 | ``` 96 | 97 | ## Customization 98 | 99 | `@neutrinojs/clean` creates some conventions to make overriding the 100 | configuration easier once you are ready to make changes. 101 | 102 | ### Plugins 103 | 104 | The following is a list of plugins and their identifiers which can be 105 | overridden: 106 | 107 | | Name | Description | NODE_ENV | 108 | | ------- | ------------------------------------ | -------- | 109 | | `clean` | Removes directories before building. | all | 110 | 111 | ## Contributing 112 | 113 | This middleware is part of the 114 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 115 | containing all resources for developing Neutrino and its core presets and 116 | middleware. Follow the 117 | [contributing guide](https://neutrinojs.org/contributing/) for details. 118 | 119 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/clean.svg 120 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/clean.svg 121 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/clean 122 | -------------------------------------------------------------------------------- /packages/clean/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | ({ pluginId = 'clean', ...opts } = {}) => 3 | (neutrino) => { 4 | const options = { 5 | verbose: neutrino.options.debug, 6 | ...opts, 7 | }; 8 | 9 | neutrino.config 10 | .plugin(pluginId) 11 | .use(require.resolve('clean-webpack-plugin'), [options]) 12 | .init((Plugin, args) => new Plugin.CleanWebpackPlugin(...args)); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/clean/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/clean", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for cleaning bundle output directories", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "clean" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/clean" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "clean-webpack-plugin": "^3.0.0" 30 | }, 31 | "peerDependencies": { 32 | "neutrino": "^9.0.0", 33 | "webpack": "^4.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/clean/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { paths: ['sample'], root: __dirname }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/compile-loader/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/compile-loader/index.js: -------------------------------------------------------------------------------- 1 | const { DuplicateRuleError } = require('neutrino/errors'); 2 | 3 | module.exports = 4 | ({ ruleId = 'compile', useId = 'babel', ...options } = {}) => 5 | (neutrino) => { 6 | if (neutrino.config.module.rules.has(ruleId)) { 7 | throw new DuplicateRuleError('@neutrinojs/compile-loader', ruleId); 8 | } 9 | 10 | neutrino.config.module 11 | .rule(ruleId) 12 | .test(options.test || neutrino.regexFromExtensions()) 13 | .when(options.include, (rule) => rule.include.merge(options.include)) 14 | .when(options.exclude, (rule) => rule.exclude.merge(options.exclude)) 15 | .use(useId) 16 | .loader(require.resolve('babel-loader')) 17 | .options({ 18 | cacheDirectory: true, 19 | babelrc: false, 20 | configFile: false, 21 | ...(options.babel || {}), 22 | }); 23 | 24 | neutrino.register('babel', (neutrino) => 25 | neutrino.config.module.rule(ruleId).use(useId).get('options'), 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/compile-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/compile-loader", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for compiling JavaScript using Babel configuration", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "compile", 10 | "babel" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/compile-loader" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "@babel/core": "^7.12.10", 31 | "babel-loader": "^8.2.2" 32 | }, 33 | "peerDependencies": { 34 | "neutrino": "^9.0.0", 35 | "webpack": "^4.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/compile-loader/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | import neutrino from '../../neutrino'; 4 | 5 | const mw = (...args) => require('..')(...args); 6 | const options = { test: /\.js$/, babel: { cacheDirectory: false } }; 7 | 8 | test('loads middleware', (t) => { 9 | t.notThrows(() => require('..')); 10 | }); 11 | 12 | test('uses middleware', (t) => { 13 | const api = new Neutrino(); 14 | 15 | t.notThrows(() => api.use(mw())); 16 | }); 17 | 18 | test('uses with options', (t) => { 19 | const api = new Neutrino(); 20 | 21 | t.notThrows(() => api.use(mw(options))); 22 | }); 23 | 24 | test('instantiates', (t) => { 25 | const api = new Neutrino(); 26 | 27 | api.use(mw()); 28 | 29 | t.notThrows(() => api.config.toConfig()); 30 | }); 31 | 32 | test('instantiates with options', (t) => { 33 | const api = new Neutrino(); 34 | 35 | api.use(mw(options)); 36 | 37 | t.notThrows(() => api.config.toConfig()); 38 | }); 39 | 40 | test('exposes babel output handler', (t) => { 41 | const api = new Neutrino(); 42 | 43 | api.use(mw()); 44 | 45 | const handler = api.outputHandlers.get('babel'); 46 | 47 | t.is(typeof handler, 'function'); 48 | }); 49 | 50 | test('exposes babel config from output', (t) => { 51 | const config = neutrino(mw()).output('babel'); 52 | 53 | t.is(typeof config, 'object'); 54 | }); 55 | 56 | test('exposes babel method', (t) => { 57 | t.is(typeof neutrino(mw()).babel, 'function'); 58 | }); 59 | 60 | test('exposes babel config from method', (t) => { 61 | t.is(typeof neutrino(mw()).babel(), 'object'); 62 | }); 63 | 64 | test('throws when used twice', (t) => { 65 | const api = new Neutrino(); 66 | api.use(mw()); 67 | t.throws( 68 | () => api.use(mw()), 69 | /@neutrinojs\/compile-loader has been used twice with the same ruleId of 'compile'/, 70 | ); 71 | }); 72 | -------------------------------------------------------------------------------- /packages/copy/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/copy/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Copy Middleware 2 | 3 | `@neutrinojs/copy` is Neutrino middleware for copying files during building. 4 | 5 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 6 | 7 | ## Requirements 8 | 9 | - Node.js 10+ 10 | - Yarn v1.2.1+, or npm v5.4+ 11 | - Neutrino 9 12 | - webpack 4 13 | 14 | ## Installation 15 | 16 | `@neutrinojs/copy` can be installed via the Yarn or npm clients. 17 | 18 | #### Yarn 19 | 20 | ```bash 21 | ❯ yarn add --dev @neutrinojs/copy 22 | ``` 23 | 24 | #### npm 25 | 26 | ```bash 27 | ❯ npm install --save-dev @neutrinojs/copy 28 | ``` 29 | 30 | ## Usage 31 | 32 | `@neutrinojs/copy` can be consumed from the Neutrino API, middleware, or 33 | presets. Require this package and plug it into Neutrino: 34 | 35 | ```js 36 | const copy = require('@neutrinojs/copy'); 37 | 38 | // Use with default options 39 | neutrino.use(copy()); 40 | 41 | // Usage shows the default values of this middleware: 42 | neutrino.use( 43 | copy({ 44 | patterns: [], 45 | options: { 46 | logLevel: neutrino.options.debug ? 'debug' : 'warn', 47 | }, 48 | pluginId: 'copy', 49 | }), 50 | ); 51 | ``` 52 | 53 | ```js 54 | // Using in .neutrinorc.js 55 | const copy = require('@neutrinojs/copy'); 56 | 57 | // Use with default options 58 | module.exports = { 59 | use: [copy()], 60 | }; 61 | 62 | // Usage shows the default values of this middleware: 63 | module.exports = { 64 | use: [ 65 | copy({ 66 | patterns: [], 67 | options: { 68 | logLevel: neutrino.options.debug ? 'debug' : 'warn', 69 | }, 70 | pluginId: 'copy', 71 | }), 72 | ], 73 | }; 74 | ``` 75 | 76 | The `patterns` and `options` are defined from the 77 | [CopyWebpackPlugin](https://github.com/kevlened/copy-webpack-plugin). See their 78 | docs for details on valid values to specify. 79 | 80 | - `patterns`: An array of patterns specifying copy operations. 81 | - `options`: An object specifying copy options. 82 | - `pluginId`: The plugin identifier. Override this to add an additional copy 83 | plugin instance. 84 | 85 | ## Customization 86 | 87 | `@neutrinojs/copy` creates some conventions to make overriding the configuration 88 | easier once you are ready to make changes. 89 | 90 | ### Plugins 91 | 92 | The following is a list of plugins and their identifiers which can be 93 | overridden: 94 | 95 | | Name | Description | NODE_ENV | 96 | | ------ | --------------------------- | -------- | 97 | | `copy` | Copy files during building. | all | 98 | 99 | ## Contributing 100 | 101 | This middleware is part of the 102 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 103 | containing all resources for developing Neutrino and its core presets and 104 | middleware. Follow the 105 | [contributing guide](https://neutrinojs.org/contributing/) for details. 106 | 107 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/copy.svg 108 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/copy.svg 109 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/copy 110 | -------------------------------------------------------------------------------- /packages/copy/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | ({ pluginId = 'copy', patterns = [], options = {} } = {}) => 3 | (neutrino) => { 4 | neutrino.config 5 | .plugin(pluginId) 6 | .use(require.resolve('copy-webpack-plugin'), [ 7 | patterns, 8 | { 9 | logLevel: neutrino.options.debug ? 'debug' : 'warn', 10 | ...options, 11 | }, 12 | ]); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/copy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/copy", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for copying files to a bundle output directory", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "copy", 10 | "copying" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/copy" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "copy-webpack-plugin": "^5.1.2" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/copy/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { 6 | patterns: ['shorthand-form', { from: 'source', to: 'dest' }], 7 | options: { ignore: /\.css$/ }, 8 | }; 9 | 10 | test('loads middleware', (t) => { 11 | t.notThrows(() => require('..')); 12 | }); 13 | 14 | test('uses middleware', (t) => { 15 | t.notThrows(() => new Neutrino().use(mw())); 16 | }); 17 | 18 | test('uses with options', (t) => { 19 | t.notThrows(() => new Neutrino().use(mw(options))); 20 | }); 21 | 22 | test('instantiates', (t) => { 23 | const api = new Neutrino(); 24 | 25 | api.use(mw()); 26 | 27 | t.notThrows(() => api.config.toConfig()); 28 | }); 29 | 30 | test('instantiates with options', (t) => { 31 | const api = new Neutrino(); 32 | 33 | api.use(mw(options)); 34 | 35 | t.notThrows(() => api.config.toConfig()); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/create-project/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/create-project/bin/create-project.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const yargs = require('yargs'); 4 | const { createEnv } = require('yeoman-environment'); 5 | const { basename, isAbsolute, join, resolve } = require('path'); 6 | 7 | const env = createEnv(); 8 | const done = (exitCode) => process.exit(exitCode || 0); 9 | const dir = resolve(__dirname, '../commands/init'); 10 | 11 | env.register(require.resolve(dir), 'create-project'); 12 | 13 | const cli = yargs 14 | .command('') 15 | .option('debug', { description: 'Run in debug mode' }) 16 | .option('registry', { description: 'Specify an alternate npm registry' }) 17 | .demandCommand(1, 'Only is required') 18 | .help() 19 | .wrap(null).argv; 20 | const directory = isAbsolute(cli._[0]) 21 | ? cli._[0] 22 | : join(process.cwd(), cli._[0]); 23 | const name = basename(directory); 24 | 25 | env.run( 26 | 'create-project', 27 | { 28 | directory, 29 | name, 30 | registry: cli.registry, 31 | debug: !!cli.debug, 32 | stdio: cli.debug ? 'inherit' : 'ignore', 33 | }, 34 | done, 35 | ); 36 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/airbnb-base/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | module.exports = neutrino().eslintrc(); 4 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/airbnb/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | module.exports = neutrino().eslintrc(); 4 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/jest/jest.config.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 4 | 5 | module.exports = neutrino().jest(); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/jest/test/simple_test.js: -------------------------------------------------------------------------------- 1 | describe('simple', () => { 2 | it('should be sane', () => { 3 | expect(false).not.toBe(true); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/karma/karma.conf.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 4 | 5 | module.exports = neutrino().karma(); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/karma/test/simple_test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | 3 | describe('simple', () => { 4 | it('should be sane', () => { 5 | assert.equal(true, !false); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/library/src/index.js: -------------------------------------------------------------------------------- 1 | export default () => 'Welcome to <%= data.name %>'; 2 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/library/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/mocha/.mocharc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 4 | 5 | module.exports = neutrino().mocha(); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/mocha/test/simple_test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | 3 | describe('simple', () => { 4 | it('should be sane', () => { 5 | assert.equal(true, !false); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/neutrino/.neutrinorc.js.ejs: -------------------------------------------------------------------------------- 1 | <% middleware.forEach(({ name, package }) => { %>const <%= name %> = require('<%= package %>'); 2 | <% })%> 3 | module.exports = { 4 | options: { 5 | root: __dirname, 6 | }, 7 | use: [<% middleware.forEach(({ name, options }) => { %> 8 | <%= name %>(<%- options %>),<% })%> 9 | ], 10 | }; 11 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/node/src/app.js: -------------------------------------------------------------------------------- 1 | const app = () => 2 | '

Welcome to <%= data.name %>

'; 3 | 4 | export default app; 5 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/node/src/index.js: -------------------------------------------------------------------------------- 1 | import { createServer } from 'http'; 2 | import app from './app'; 3 | 4 | const port = process.env.PORT || 3000; 5 | 6 | createServer((request, response) => response.end(app())).listen(port, () => 7 | process.stdout.write(`Running on :${port}\n`), 8 | ); 9 | 10 | if (module.hot) { 11 | module.hot.accept('./app'); 12 | } 13 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/node/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/preact/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | } 4 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/preact/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import './App.css'; 3 | 4 | export default class App extends Component { 5 | state = { 6 | name: '<%= data.name %>', 7 | }; 8 | 9 | render() { 10 | const { name } = this.state; 11 | return ( 12 |
13 |

14 | Welcome to 15 | {name} 16 |

17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/preact/src/index.jsx: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact'; 2 | 3 | const root = document.getElementById('root'); 4 | const load = async () => { 5 | const { default: App } = await import('./App'); 6 | 7 | render(, root); 8 | }; 9 | 10 | // This is needed for Hot Module Replacement 11 | if (module.hot) { 12 | module.hot.accept('./App', () => requestAnimationFrame(load)); 13 | } 14 | 15 | load(); 16 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/preact/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react-components/src/components/Example/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | // From https://reactjs.org/docs/hooks-state.html 4 | export default function Example() { 5 | // Declare a new state variable, which we'll call "count" 6 | const [count, setCount] = useState(0); 7 | const message = `You clicked ${count} times`; 8 | 9 | return ( 10 |
11 |

{message}

12 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react-components/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import Example from './components/Example'; 4 | 5 | render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react-components/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | } 4 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { hot } from 'react-hot-loader'; 2 | import React from 'react'; 3 | import './App.css'; 4 | 5 | const message = 'Welcome to <%= data.name %>'; 6 | const App = () => ( 7 |
8 |

{message}

9 |
10 | ); 11 | 12 | export default hot(module)(App); 13 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import App from './App'; 4 | 5 | render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/react/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/standardjs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('neutrino'); 2 | 3 | module.exports = neutrino().eslintrc(); 4 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/vue/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | 4 | export default new Vue({ 5 | el: '#root', 6 | render: (h) => h(App), 7 | }); 8 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/vue/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/web/src/index.js: -------------------------------------------------------------------------------- 1 | const root = document.getElementById('root'); 2 | 3 | root.innerHTML = 4 | '

Welcome to <%= data.name %>

'; 5 | 6 | // This is needed for Hot Module Replacement 7 | if (module.hot) { 8 | module.hot.accept(); 9 | } 10 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/templates/web/webpack.config.js: -------------------------------------------------------------------------------- 1 | // Whilst the configuration object can be modified here, the recommended way of making 2 | // changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead. 3 | // Neutrino's inspect feature can be used to view/export the generated configuration. 4 | const neutrino = require('neutrino'); 5 | 6 | module.exports = neutrino().webpack(); 7 | -------------------------------------------------------------------------------- /packages/create-project/commands/init/utils.js: -------------------------------------------------------------------------------- 1 | const { compile } = require('ejs'); 2 | const { readFileSync } = require('fs-extra'); 3 | const { stringify } = require('javascript-stringify'); 4 | const { join } = require('path'); 5 | 6 | const RE_INDENT = /^(?!\s*$)/gm; 7 | const isYarn = 8 | process.env.npm_config_user_agent && 9 | process.env.npm_config_user_agent.includes('yarn'); 10 | const cli = isYarn ? 'yarn' : 'npm'; 11 | const yarnReplacers = new Map(); 12 | const npmReplacers = new Map(); 13 | 14 | yarnReplacers.set(/^run /, ''); 15 | yarnReplacers.set(/^install /, 'add '); 16 | yarnReplacers.set(/--save-dev/, '--dev'); 17 | npmReplacers.set(/--dev/, '--save-dev'); 18 | npmReplacers.set(/^add /, 'install '); 19 | npmReplacers.set(/--fix/, '-- --fix'); 20 | 21 | const packageManager = (command, registry) => { 22 | if (!command) { 23 | return cli; 24 | } 25 | 26 | const formatted = [...(isYarn ? yarnReplacers : npmReplacers)].reduce( 27 | (command, [matcher, replacement]) => 28 | matcher.test(command) ? command.replace(matcher, replacement) : command, 29 | command, 30 | ); 31 | 32 | return registry 33 | ? `${cli} --registry ${registry} ${formatted}` 34 | : `${cli} ${formatted}`; 35 | }; 36 | 37 | const packageLint = (jsx = false, vue = false, test = false) => { 38 | // The list of extensions here needs to be kept in sync with the extension 39 | // list defined by neutrino/extensions.source. Modifying a value here should 40 | // have an accompanying change there as well. We can't pull in neutrino here 41 | // as that would potentially give us conflicting versions in node_modules. 42 | const exts = ['mjs', vue && 'vue', jsx && 'jsx', 'js'] 43 | .filter(Boolean) 44 | .join(','); 45 | const dirs = ['src', test && 'test'].filter(Boolean).join(' '); 46 | 47 | return { 48 | scripts: { 49 | lint: `eslint --cache --format codeframe --ext ${exts} ${dirs}`, 50 | }, 51 | }; 52 | }; 53 | 54 | const rcTemplate = compile( 55 | readFileSync( 56 | join(__dirname, 'templates/neutrino/.neutrinorc.js.ejs'), 57 | ).toString(), 58 | ); 59 | 60 | const getNeutrinorcOptions = (name, project) => { 61 | if (!project.options) { 62 | return ''; 63 | } 64 | 65 | const [head, ...tail] = stringify(project.options(name), null, 2).split('\n'); 66 | 67 | return `${head}\n${tail.join('\n').replace(RE_INDENT, ' ')}`; 68 | }; 69 | 70 | module.exports = { 71 | getNeutrinorcOptions, 72 | packageLint, 73 | packageManager, 74 | rcTemplate, 75 | }; 76 | -------------------------------------------------------------------------------- /packages/create-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/create-project", 3 | "version": "9.5.0", 4 | "description": "Scaffold new Neutrino projects with a CLI helper", 5 | "bin": { 6 | "create-project": "./bin/create-project.js" 7 | }, 8 | "scripts": { 9 | "start": "./bin/create-project init" 10 | }, 11 | "files": [ 12 | "bin", 13 | "commands" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/create-project" 19 | }, 20 | "author": "Hassan Ali ", 21 | "license": "MPL-2.0", 22 | "keywords": [ 23 | "neutrino", 24 | "create", 25 | "project", 26 | "app", 27 | "library", 28 | "react", 29 | "preact", 30 | "vue", 31 | "node" 32 | ], 33 | "publishConfig": { 34 | "access": "public" 35 | }, 36 | "engines": { 37 | "node": ">=10", 38 | "npm": ">=5.4.0", 39 | "yarn": ">=1.16.0" 40 | }, 41 | "dependencies": { 42 | "chalk": "^4.1.0", 43 | "deepmerge": "^1.5.2", 44 | "ejs": "^3.1.5", 45 | "fs-extra": "^9.0.1", 46 | "javascript-stringify": "^2.0.1", 47 | "yargs": "^16.2.0", 48 | "yeoman-environment": "^2.10.3", 49 | "yeoman-generator": "^4.12.0" 50 | }, 51 | "devDependencies": { 52 | "yeoman-assert": "^3.1.1", 53 | "yeoman-test": "^2.7.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/dev-server/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/dev-server/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Dev Server Middleware 2 | 3 | `@neutrinojs/dev-server` is Neutrino middleware for starting a webpack Dev 4 | Server for fast development cycles. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | - webpack-dev-server 3 15 | 16 | ## Installation 17 | 18 | `@neutrinojs/dev-server` can be installed via the Yarn or npm clients. 19 | 20 | #### Yarn 21 | 22 | ```bash 23 | ❯ yarn add --dev @neutrinojs/dev-server 24 | ``` 25 | 26 | #### npm 27 | 28 | ```bash 29 | ❯ npm install --save-dev @neutrinojs/dev-server 30 | ``` 31 | 32 | ## Usage 33 | 34 | `@neutrinojs/dev-server` can be consumed from the Neutrino API, middleware, or 35 | presets. Require this package and plug it into Neutrino: 36 | 37 | ```js 38 | const devServer = require('@neutrinojs/dev-server'); 39 | 40 | // Usage with default options 41 | neutrino.use(devServer()); 42 | 43 | // Usage with custom options (default options are shown) 44 | neutrino.use( 45 | devServer({ 46 | port: 5000, 47 | hot: true, 48 | // Redirect 404s to index.html, so that apps that use the HTML 5 History API work. 49 | historyApiFallback: true, 50 | // Only display compile duration and errors/warnings, to reduce noise when rebuilding. 51 | stats: { 52 | all: false, 53 | errors: true, 54 | timings: true, 55 | warnings: true, 56 | }, 57 | }), 58 | ); 59 | ``` 60 | 61 | ```js 62 | // Using in .neutrinorc.js 63 | const devServer = require('@neutrinojs/dev-server'); 64 | 65 | // Usage with default options 66 | module.exports = { 67 | use: [devServer()], 68 | }; 69 | 70 | // Usage with custom options (default options are shown) 71 | module.exports = { 72 | use: [ 73 | devServer({ 74 | port: 5000, 75 | hot: true, 76 | // Redirect 404s to index.html, so that apps that use the HTML 5 History API work. 77 | historyApiFallback: true, 78 | // Only display compile duration and errors/warnings, to reduce noise when rebuilding. 79 | stats: { 80 | all: false, 81 | errors: true, 82 | timings: true, 83 | warnings: true, 84 | }, 85 | }), 86 | ], 87 | }; 88 | ``` 89 | 90 | By default this middleware will start a development server with Hot Module 91 | Replacement support on `http://localhost:5000`. To enable HMR with your 92 | application, read the documentation of corresponding Neutrino preset or 93 | middleware. 94 | 95 | ## Middleware options 96 | 97 | `@neutrinojs/dev-server` optionally accepts an object with several options to 98 | override the default behavior. This object, as seen used above, can accept any 99 | [property that is accepted by webpack Dev Server](https://webpack.js.org/configuration/dev-server/). 100 | 101 | ## Contributing 102 | 103 | This middleware is part of the 104 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 105 | containing all resources for developing Neutrino and its core presets and 106 | middleware. Follow the 107 | [contributing guide](https://neutrinojs.org/contributing/) for details. 108 | 109 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/dev-server.svg 110 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/dev-server.svg 111 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/dev-server 112 | -------------------------------------------------------------------------------- /packages/dev-server/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | (options = {}) => 3 | (neutrino) => { 4 | neutrino.config.devServer.merge({ 5 | port: 5000, 6 | hot: true, 7 | // Redirect 404s to index.html, so that apps that use the HTML 5 History API work. 8 | historyApiFallback: true, 9 | // Display any webpack compile errors (but not warnings) on an in-page overlay. 10 | overlay: true, 11 | // Only display compile duration and errors/warnings, to reduce noise when rebuilding. 12 | stats: { 13 | all: false, 14 | errors: true, 15 | timings: true, 16 | warnings: true, 17 | }, 18 | ...options, 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/dev-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/dev-server", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for starting a webpack-dev-server", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "webpack", 10 | "dev", 11 | "server", 12 | "hmr", 13 | "hot module replacement" 14 | ], 15 | "author": "Constantine Genchevsky ", 16 | "license": "MPL-2.0", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/neutrinojs/neutrino.git", 20 | "directory": "packages/dev-server" 21 | }, 22 | "homepage": "https://neutrinojs.org", 23 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 24 | "publishConfig": { 25 | "access": "public" 26 | }, 27 | "engines": { 28 | "node": ">=10", 29 | "npm": ">=5.4.0", 30 | "yarn": ">=1.2.1" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0", 35 | "webpack-dev-server": "^3.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/dev-server/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { host: '192.168.1.10', port: 3000, https: true }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/eslint/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | eslintrc.js 3 | -------------------------------------------------------------------------------- /packages/eslint/eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('../neutrino'); 2 | const middleware = require('.'); 3 | 4 | module.exports = neutrino({ 5 | use: middleware(), 6 | options: { 7 | root: __dirname, 8 | }, 9 | }).eslintrc(); 10 | -------------------------------------------------------------------------------- /packages/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/eslint", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for linting source code using ESLint", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "lint", 10 | "eslint" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/eslint" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "babel-eslint": "^10.1.0", 31 | "eslint-loader": "^4.0.2", 32 | "eslint-plugin-babel": "^5.3.1" 33 | }, 34 | "peerDependencies": { 35 | "eslint": "^6.0.0 || ^7.0.0", 36 | "neutrino": "^9.0.0", 37 | "webpack": "^4.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/font-loader/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/font-loader/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Font Loader Middleware 2 | 3 | `@neutrinojs/font-loader` is Neutrino middleware for loading and importing font 4 | files from modules. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | 15 | ## Installation 16 | 17 | `@neutrinojs/font-loader` can be installed via the Yarn or npm clients. 18 | 19 | #### Yarn 20 | 21 | ```bash 22 | ❯ yarn add --dev @neutrinojs/font-loader 23 | ``` 24 | 25 | #### npm 26 | 27 | ```bash 28 | ❯ npm install --save-dev @neutrinojs/font-loader 29 | ``` 30 | 31 | ## Usage 32 | 33 | `@neutrinojs/font-loader` can be consumed from the Neutrino API, middleware, or 34 | presets. Require this package and plug it into Neutrino: 35 | 36 | ```js 37 | const fonts = require('@neutrinojs/font-loader'); 38 | 39 | // Use with default options 40 | neutrino.use(fonts()); 41 | 42 | // Usage showing default options 43 | neutrino.use( 44 | fonts({ 45 | name: 46 | process.env.NODE_ENV === 'production' 47 | ? 'assets/[name].[hash:8].[ext]' 48 | : 'assets/[name].[ext]', 49 | }), 50 | ); 51 | ``` 52 | 53 | ```js 54 | // Using in .neutrinorc.js 55 | const fonts = require('@neutrinojs/font-loader'); 56 | 57 | // Use with default options 58 | module.exports = { 59 | use: [fonts()], 60 | }; 61 | 62 | // Usage showing default options 63 | module.exports = { 64 | use: [ 65 | fonts({ 66 | name: 67 | process.env.NODE_ENV === 'production' 68 | ? 'assets/[name].[hash:8].[ext]' 69 | : 'assets/[name].[ext]', 70 | }), 71 | ], 72 | }; 73 | ``` 74 | 75 | - `name`: The template used by `file-loader` to determine the output filename. 76 | 77 | ## Customization 78 | 79 | `@neutrinojs/font-loader` creates some conventions to make overriding the 80 | configuration easier once you are ready to make changes. 81 | 82 | ### Rules 83 | 84 | The following is a list of rules and their identifiers which can be overridden: 85 | 86 | | Name | Description | NODE_ENV | 87 | | ------ | --------------------------------------------------------------------------------------------------------- | -------- | 88 | | `font` | Allows importing EOT, TTF, WOFF and WOFF2 font files from modules. Contains a single loader named `file`. | all | 89 | 90 | ## Contributing 91 | 92 | This middleware is part of the 93 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 94 | containing all resources for developing Neutrino and its core presets and 95 | middleware. Follow the 96 | [contributing guide](https://neutrinojs.org/contributing/) for details. 97 | 98 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/font-loader.svg 99 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/font-loader.svg 100 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/font-loader 101 | -------------------------------------------------------------------------------- /packages/font-loader/index.js: -------------------------------------------------------------------------------- 1 | const { DuplicateRuleError } = require('neutrino/errors'); 2 | 3 | module.exports = 4 | (options = {}) => 5 | (neutrino) => { 6 | const ruleId = 'font'; 7 | const isProduction = process.env.NODE_ENV === 'production'; 8 | const defaultOptions = { 9 | name: isProduction 10 | ? 'assets/[name].[hash:8].[ext]' 11 | : 'assets/[name].[ext]', 12 | }; 13 | 14 | if (neutrino.config.module.rules.has(ruleId)) { 15 | throw new DuplicateRuleError('@neutrinojs/font-loader', ruleId); 16 | } 17 | 18 | neutrino.config.module 19 | .rule(ruleId) 20 | .test(/\.(eot|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/) 21 | .use('file') 22 | .loader(require.resolve('file-loader')) 23 | .options({ ...defaultOptions, ...options }); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/font-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/font-loader", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for importing and loading font files from modules", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "font" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/font-loader" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "file-loader": "^6.2.0" 30 | }, 31 | "peerDependencies": { 32 | "neutrino": "^9.0.0", 33 | "webpack": "^4.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/font-loader/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { name: '[name].[ext]' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | 35 | test('throws when used twice', (t) => { 36 | const api = new Neutrino(); 37 | api.use(mw()); 38 | t.throws( 39 | () => api.use(mw()), 40 | /@neutrinojs\/font-loader has been used twice with the same ruleId of 'font'/, 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/html-loader/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/html-loader/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino HTML Loader Middleware 2 | 3 | `@neutrinojs/html-loader` is Neutrino middleware for loading and importing HTML 4 | files from modules. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | 15 | ## Installation 16 | 17 | `@neutrinojs/html-loader` can be installed via the Yarn or npm clients. 18 | 19 | #### Yarn 20 | 21 | ```bash 22 | ❯ yarn add --dev @neutrinojs/html-loader 23 | ``` 24 | 25 | #### npm 26 | 27 | ```bash 28 | ❯ npm install --save-dev @neutrinojs/html-loader 29 | ``` 30 | 31 | ## Usage 32 | 33 | `@neutrinojs/html-loader` can be consumed from the Neutrino API, middleware, or 34 | presets. Require this package and plug it into Neutrino: 35 | 36 | ```js 37 | const html = require('@neutrinojs/html-loader'); 38 | 39 | // Use with default options 40 | neutrino.use(html()); 41 | 42 | // Usage showing default options 43 | neutrino.use( 44 | html({ 45 | attrs: ['img:src', 'link:href'], 46 | }), 47 | ); 48 | ``` 49 | 50 | ```js 51 | // Using in .neutrinorc.js 52 | const html = require('@neutrinojs/html-loader'); 53 | 54 | // Use with default options 55 | module.exports = { 56 | use: [html()], 57 | }; 58 | 59 | // Usage showing default options 60 | module.exports = { 61 | use: [ 62 | html({ 63 | attrs: ['img:src', 'link:href'], 64 | }), 65 | ], 66 | }; 67 | ``` 68 | 69 | The options object passed to this middleware will be passed as options to the 70 | html-loader used to load HTML files. 71 | 72 | ## Customization 73 | 74 | `@neutrinojs/html-loader` creates some conventions to make overriding the 75 | configuration easier once you are ready to make changes. 76 | 77 | ### Rules 78 | 79 | The following is a list of rules and their identifiers which can be overridden: 80 | 81 | | Name | Description | NODE_ENV | 82 | | ------ | -------------------------------------------------------------------------------- | -------- | 83 | | `html` | Allows importing HTML files from modules. Contains a single loader named `html`. | all | 84 | 85 | ## Contributing 86 | 87 | This middleware is part of the 88 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 89 | containing all resources for developing Neutrino and its core presets and 90 | middleware. Follow the 91 | [contributing guide](https://neutrinojs.org/contributing/) for details. 92 | 93 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/html-loader.svg 94 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/html-loader.svg 95 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/html-loader 96 | -------------------------------------------------------------------------------- /packages/html-loader/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | (options = {}) => 3 | (neutrino) => { 4 | neutrino.config.module 5 | .rule('html') 6 | .test(neutrino.regexFromExtensions(['html'])) 7 | .use('html') 8 | .loader(require.resolve('html-loader')) 9 | .options({ 10 | // Override html-loader's default attrs of `['img:src']` 11 | // so it also parses favicon images (``). 12 | // TODO: Remove once html-loader 1.0.0 is released: 13 | // https://github.com/webpack-contrib/html-loader/issues/17 14 | attrs: ['img:src', 'link:href'], 15 | ...options, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/html-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/html-loader", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for importing and loading HTML files from modules", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "html" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/html-loader" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "html-loader": "^0.5.5" 30 | }, 31 | "peerDependencies": { 32 | "neutrino": "^9.0.0", 33 | "webpack": "^4.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/html-loader/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { name: 'alpha.beta' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/html-template/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/html-template/index.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | const { ConfigurationError } = require('neutrino/errors'); 3 | 4 | module.exports = ({ pluginId = 'html', ...options } = {}) => { 5 | if ('links' in options && !('template' in options)) { 6 | throw new ConfigurationError( 7 | 'The default Neutrino HTML template no longer supports the "links" option. ' + 8 | 'To set a favicon use the "favicon" option instead. For stylesheets either ' + 9 | 'import the equivalent npm package from JS, or if using a CDN is preferred, ' + 10 | 'then copy the default HTML template into your repository (where it can be ' + 11 | 'customised as desired) and set the "template" option to its path.', 12 | ); 13 | } 14 | 15 | return (neutrino) => { 16 | neutrino.config 17 | .plugin(pluginId) 18 | .use(require.resolve('html-webpack-plugin'), [ 19 | { 20 | // Use a custom template that has more features (appMountId, lang) than the default: 21 | // https://github.com/jantimon/html-webpack-plugin/blob/master/default_index.ejs 22 | template: resolve(__dirname, 'template.ejs'), 23 | appMountId: 'root', 24 | lang: 'en', 25 | meta: { 26 | viewport: 'width=device-width, initial-scale=1', 27 | ...options.meta, 28 | }, 29 | ...options, 30 | }, 31 | ]); 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /packages/html-template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/html-template", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for automatic HTML file generation from metadata", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "html", 10 | "template" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/html-template" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "html-webpack-plugin": "^4.5.0" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/html-template/template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/html-template/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { title: 'Alpha Beta', appMountId: 'app' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | const api = new Neutrino(); 13 | 14 | t.notThrows(() => api.use(mw())); 15 | }); 16 | 17 | test('uses with options', (t) => { 18 | const api = new Neutrino(); 19 | 20 | t.notThrows(() => api.use(mw(options))); 21 | }); 22 | 23 | test('instantiates', (t) => { 24 | const api = new Neutrino(); 25 | 26 | api.use(mw()); 27 | 28 | t.notThrows(() => api.config.toConfig()); 29 | }); 30 | 31 | test('instantiates with options', (t) => { 32 | const api = new Neutrino(); 33 | 34 | api.use(mw(options)); 35 | 36 | t.notThrows(() => api.config.toConfig()); 37 | }); 38 | 39 | test('throws when links defined with default template', (t) => { 40 | const api = new Neutrino(); 41 | 42 | t.throws( 43 | () => api.use(mw({ links: [] })), 44 | /no longer supports the "links" option/, 45 | ); 46 | }); 47 | 48 | test('does not throw when links defined with custom template', (t) => { 49 | const api = new Neutrino(); 50 | 51 | t.notThrows(() => api.use(mw({ links: [], template: 'custom.html' }))); 52 | }); 53 | -------------------------------------------------------------------------------- /packages/image-loader/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/image-loader/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Image Loader Middleware 2 | 3 | `@neutrinojs/image-loader` is Neutrino middleware for loading and importing 4 | image files from modules. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | 15 | ## Installation 16 | 17 | `@neutrinojs/image-loader` can be installed via the Yarn or npm clients. 18 | 19 | #### Yarn 20 | 21 | ```bash 22 | ❯ yarn add --dev @neutrinojs/image-loader 23 | ``` 24 | 25 | #### npm 26 | 27 | ```bash 28 | ❯ npm install --save-dev @neutrinojs/image-loader 29 | ``` 30 | 31 | ## Usage 32 | 33 | `@neutrinojs/image-loader` can be consumed from the Neutrino API, middleware, or 34 | presets. Require this package and plug it into Neutrino: 35 | 36 | ```js 37 | const images = require('@neutrinojs/image-loader'); 38 | 39 | // Use with default options 40 | neutrino.use(images()); 41 | 42 | // Usage showing default options 43 | neutrino.use( 44 | images({ 45 | limit: 8192, 46 | name: 47 | process.env.NODE_ENV === 'production' 48 | ? 'assets/[name].[hash:8].[ext]' 49 | : 'assets/[name].[ext]', 50 | }), 51 | ); 52 | ``` 53 | 54 | ```js 55 | // Using in .neutrinorc.js 56 | const images = require('@neutrinojs/image-loader'); 57 | 58 | // Use with default options 59 | module.exports = { 60 | use: [images()], 61 | }; 62 | 63 | // Usage showing default options 64 | module.exports = { 65 | use: [ 66 | images({ 67 | limit: 8192, 68 | name: 69 | process.env.NODE_ENV === 'production' 70 | ? 'assets/[name].[hash:8].[ext]' 71 | : 'assets/[name].[ext]', 72 | }), 73 | ], 74 | }; 75 | ``` 76 | 77 | - `limit`: Return a Data URL instead of outputting a file, if the file is 78 | smaller than a byte limit. 79 | - `name`: The template used by `file-loader` to determine the output filename. 80 | 81 | ## Customization 82 | 83 | `@neutrinojs/image-loader` creates some conventions to make overriding the 84 | configuration easier once you are ready to make changes. 85 | 86 | ### Rules 87 | 88 | The following is a list of rules and their identifiers which can be overridden: 89 | 90 | | Name | Description | NODE_ENV | 91 | | ------- | ------------------------------------------------------------------------------------------------------------ | -------- | 92 | | `image` | Allows importing ICO, JPEG, PNG, GIF, SVG and WEBP files from modules. Contains a single loader named `url`. | all | 93 | 94 | ## Contributing 95 | 96 | This middleware is part of the 97 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 98 | containing all resources for developing Neutrino and its core presets and 99 | middleware. Follow the 100 | [contributing guide](https://neutrinojs.org/contributing/) for details. 101 | 102 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/image-loader.svg 103 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/image-loader.svg 104 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/image-loader 105 | -------------------------------------------------------------------------------- /packages/image-loader/index.js: -------------------------------------------------------------------------------- 1 | const { DuplicateRuleError } = require('neutrino/errors'); 2 | 3 | module.exports = 4 | (options = {}) => 5 | (neutrino) => { 6 | const ruleId = 'image'; 7 | const isProduction = process.env.NODE_ENV === 'production'; 8 | const defaultOptions = { 9 | limit: 8192, 10 | name: isProduction 11 | ? 'assets/[name].[hash:8].[ext]' 12 | : 'assets/[name].[ext]', 13 | }; 14 | 15 | if (neutrino.config.module.rules.has(ruleId)) { 16 | throw new DuplicateRuleError('@neutrinojs/image-loader', ruleId); 17 | } 18 | 19 | neutrino.config.module 20 | .rule(ruleId) 21 | .test(/\.(ico|png|jpg|jpeg|gif|svg|webp)(\?v=\d+\.\d+\.\d+)?$/) 22 | .use('url') 23 | .loader(require.resolve('url-loader')) 24 | .options({ ...defaultOptions, ...options }); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/image-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/image-loader", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for importing and loading image files from modules", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "image" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/image-loader" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "file-loader": "^6.2.0", 30 | "url-loader": "^4.1.1" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/image-loader/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { limit: 1024, name: '[name].[ext]' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | 35 | test('throws when used twice', (t) => { 36 | const api = new Neutrino(); 37 | api.use(mw()); 38 | t.throws( 39 | () => api.use(mw()), 40 | /@neutrinojs\/image-loader has been used twice with the same ruleId of 'image'/, 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/jest/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/jest", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for testing Neutrino projects with Jest", 5 | "main": "src/index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "jest" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/jest" 17 | }, 18 | "homepage": "https://neutrinojs.org", 19 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "@babel/core": "^7.12.10", 30 | "babel-core": "^7.0.0-bridge.0", 31 | "babel-jest": "^26.6.3", 32 | "deepmerge": "^1.5.2", 33 | "eslint-plugin-jest": "^23.20.0", 34 | "lodash.omit": "^4.5.0" 35 | }, 36 | "peerDependencies": { 37 | "jest": "^24.0.0 || ^25.0.0 || ^26.0.0", 38 | "neutrino": "^9.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/jest/src/file-mock.js: -------------------------------------------------------------------------------- 1 | module.exports = 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /packages/jest/src/style-mock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /packages/jest/src/transformer.js: -------------------------------------------------------------------------------- 1 | const { createTransformer } = require('babel-jest'); 2 | 3 | const babelOptions = JSON.parse(process.env.JEST_BABEL_OPTIONS); 4 | 5 | module.exports = createTransformer(babelOptions); 6 | -------------------------------------------------------------------------------- /packages/karma/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/karma/index.js: -------------------------------------------------------------------------------- 1 | const babelMerge = require('babel-merge'); 2 | const merge = require('deepmerge'); 3 | const omit = require('lodash.omit'); 4 | const { join } = require('path'); 5 | 6 | module.exports = 7 | (options = {}) => 8 | (neutrino) => { 9 | const lintRule = neutrino.config.module.rules.get('lint'); 10 | if (lintRule) { 11 | lintRule.use('eslint').tap( 12 | // Don't adjust the lint configuration for projects using their own .eslintrc. 13 | (lintOptions) => 14 | lintOptions.useEslintrc 15 | ? lintOptions 16 | : merge(lintOptions, { 17 | baseConfig: { 18 | env: { 19 | mocha: true, 20 | }, 21 | }, 22 | }), 23 | ); 24 | } 25 | 26 | neutrino.register('karma', (neutrino) => (config) => { 27 | if (neutrino.config.module.rules.has('compile')) { 28 | neutrino.config.module 29 | .rule('compile') 30 | .use('babel') 31 | .tap((options) => 32 | babelMerge(options, { 33 | plugins: [require.resolve('babel-plugin-istanbul')], 34 | }), 35 | ); 36 | } 37 | 38 | const tests = join(neutrino.options.tests, '**/*_test.js'); 39 | const sources = join(neutrino.options.source, '**/*.js*'); 40 | 41 | config.set( 42 | merge( 43 | { 44 | basePath: neutrino.options.root, 45 | browsers: [process.env.CI ? 'ChromeCI' : 'ChromeHeadless'], 46 | customLaunchers: { 47 | ChromeCI: { 48 | base: 'ChromeHeadless', 49 | flags: ['--no-sandbox'], 50 | }, 51 | }, 52 | frameworks: ['mocha'], 53 | files: [ 54 | { 55 | pattern: tests, 56 | watched: false, 57 | included: true, 58 | served: true, 59 | }, 60 | ], 61 | plugins: [ 62 | require.resolve('karma-webpack'), 63 | require.resolve('karma-chrome-launcher'), 64 | require.resolve('karma-coverage'), 65 | require.resolve('karma-mocha'), 66 | require.resolve('karma-mocha-reporter'), 67 | ], 68 | preprocessors: { 69 | [tests]: ['webpack'], 70 | [sources]: ['webpack'], 71 | }, 72 | webpackMiddleware: { 73 | // Only display webpack compile duration and errors/warnings, since 74 | // the focus should be on the output from the tests/karma instead. 75 | stats: { 76 | all: false, 77 | errors: true, 78 | timings: true, 79 | warnings: true, 80 | }, 81 | }, 82 | webpack: omit(neutrino.config.toConfig(), ['entry']), 83 | reporters: ['mocha', 'coverage'], 84 | coverageReporter: { 85 | dir: '.coverage', 86 | reporters: [ 87 | { type: 'html', subdir: 'report-html' }, 88 | { type: 'lcov', subdir: 'report-lcov' }, 89 | ], 90 | }, 91 | }, 92 | options, 93 | ), 94 | ); 95 | 96 | return config; 97 | }); 98 | }; 99 | -------------------------------------------------------------------------------- /packages/karma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/karma", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for testing Neutrino projects with Karma", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "karma", 10 | "mocha", 11 | "chrome" 12 | ], 13 | "author": "Eli Perelman ", 14 | "license": "MPL-2.0", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/karma" 19 | }, 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "engines": { 24 | "node": ">=10", 25 | "npm": ">=5.4.0", 26 | "yarn": ">=1.2.1" 27 | }, 28 | "dependencies": { 29 | "@babel/core": "^7.12.10", 30 | "babel-merge": "^3.0.0", 31 | "babel-plugin-istanbul": "^6.0.0", 32 | "deepmerge": "^1.5.2", 33 | "karma-chrome-launcher": "^3.1.0", 34 | "karma-coverage": "^2.0.3", 35 | "karma-mocha": "^2.0.1", 36 | "karma-mocha-reporter": "^2.2.5", 37 | "karma-webpack": "^4.0.2", 38 | "lodash.omit": "^4.5.0", 39 | "mocha-coverage-reporter": "^0.0.1" 40 | }, 41 | "peerDependencies": { 42 | "karma": "^4.0.0 || ^5.0.0", 43 | "karma-cli": "^2.0.0", 44 | "mocha": "^6.0.0 || ^7.0.0 || ^8.0.0", 45 | "neutrino": "^9.0.0", 46 | "webpack": "^4.0.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/karma/test/karma_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import lint from '../../eslint'; 3 | import Neutrino from '../../neutrino/Neutrino'; 4 | import neutrino from '../../neutrino'; 5 | 6 | const mw = (...args) => require('..')(...args); 7 | const originalNodeEnv = process.env.NODE_ENV; 8 | 9 | test.afterEach(() => { 10 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 11 | process.env.NODE_ENV = originalNodeEnv; 12 | }); 13 | 14 | test('loads middleware', (t) => { 15 | t.notThrows(() => require('..')); 16 | }); 17 | 18 | test('uses middleware', (t) => { 19 | t.notThrows(() => { 20 | const api = new Neutrino(); 21 | api.use(mw()); 22 | }); 23 | }); 24 | 25 | test('instantiates', (t) => { 26 | const api = new Neutrino(); 27 | api.use(mw()); 28 | 29 | t.notThrows(() => api.config.toConfig()); 30 | }); 31 | 32 | test('instantiates in development', (t) => { 33 | process.env.NODE_ENV = 'development'; 34 | const api = new Neutrino(); 35 | api.use(mw()); 36 | 37 | t.notThrows(() => api.config.toConfig()); 38 | }); 39 | 40 | test('instantiates in production', (t) => { 41 | process.env.NODE_ENV = 'production'; 42 | const api = new Neutrino(); 43 | api.use(mw()); 44 | 45 | t.notThrows(() => api.config.toConfig()); 46 | }); 47 | 48 | test('exposes karma output handler', (t) => { 49 | const api = new Neutrino(); 50 | api.use(mw()); 51 | 52 | const handler = api.outputHandlers.get('karma'); 53 | 54 | t.is(typeof handler, 'function'); 55 | }); 56 | 57 | test('exposes karma config from output', (t) => { 58 | // Karma's config handler returns a function. 59 | // Force evaluation by calling it. 60 | const fakeKarma = new Map(); 61 | const config = neutrino(mw()).output('karma')(fakeKarma); 62 | 63 | t.is(config, fakeKarma); 64 | }); 65 | 66 | test('exposes karma method', (t) => { 67 | t.is(typeof neutrino(mw()).karma, 'function'); 68 | }); 69 | 70 | test('exposes karma config from method', (t) => { 71 | // Karma's config handler returns a function. 72 | // Force evaluation by calling it. 73 | const fakeKarma = new Map(); 74 | const config = neutrino(mw()).karma()(fakeKarma); 75 | 76 | t.is(config, fakeKarma); 77 | }); 78 | 79 | test('uses middleware with options', (t) => { 80 | // Karma's config handler returns a function. 81 | // Force evaluation by calling it. 82 | const fakeKarma = new Map(); 83 | const config = neutrino( 84 | mw({ 85 | webpackMiddleware: { 86 | stats: { 87 | errors: false, 88 | }, 89 | }, 90 | }), 91 | ).karma()(fakeKarma); 92 | 93 | // Since we are faking out the Karma API with a Map, we need to get the 94 | // object back out of the map and check that the merge happened correctly. 95 | const [options] = [...config][0]; 96 | 97 | t.is(options.webpackMiddleware.stats.errors, false); 98 | }); 99 | 100 | test('updates lint config by default', (t) => { 101 | const api = new Neutrino(); 102 | api.use(lint()); 103 | api.use(mw()); 104 | const options = api.config.module.rule('lint').use('eslint').get('options'); 105 | t.deepEqual(options.baseConfig.env, { 106 | es6: true, 107 | mocha: true, 108 | }); 109 | }); 110 | 111 | test('does not update lint config if useEslintrc true', (t) => { 112 | const api = new Neutrino(); 113 | api.use(lint({ eslint: { useEslintrc: true } })); 114 | api.use(mw()); 115 | const options = api.config.module.rule('lint').use('eslint').get('options'); 116 | t.deepEqual(options.baseConfig, {}); 117 | }); 118 | -------------------------------------------------------------------------------- /packages/library/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/library/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/library", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building distributable libraries", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "library", 10 | "node", 11 | "web", 12 | "umd", 13 | "amd", 14 | "require", 15 | "commonjs", 16 | "commonjs2", 17 | "imports" 18 | ], 19 | "author": "Eli Perelman ", 20 | "license": "MPL-2.0", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/neutrinojs/neutrino.git", 24 | "directory": "packages/library" 25 | }, 26 | "homepage": "https://neutrinojs.org", 27 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "engines": { 32 | "node": ">=10", 33 | "npm": ">=5.4.0", 34 | "yarn": ">=1.2.1" 35 | }, 36 | "dependencies": { 37 | "@babel/core": "^7.12.10", 38 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 39 | "@babel/preset-env": "^7.12.11", 40 | "@neutrinojs/banner": "9.5.0", 41 | "@neutrinojs/clean": "9.5.0", 42 | "@neutrinojs/compile-loader": "9.5.0", 43 | "babel-merge": "^3.0.0", 44 | "deepmerge": "^1.5.2", 45 | "webpack-node-externals": "^1.7.2" 46 | }, 47 | "peerDependencies": { 48 | "neutrino": "^9.0.0", 49 | "webpack": "^4.0.0", 50 | "webpack-cli": "^3.0.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/migrate/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/migrate/README.md: -------------------------------------------------------------------------------- 1 | # Migrate a Neutrino Project 2 | 3 | `@neutrinojs/migrate` can assist with some of the changes needed to migrate to 4 | Neutrino 9. 5 | 6 | ## Getting Started 7 | 8 | The `npx @neutrinojs/migrate` command starts the process. Let's take a look at 9 | the help output of migrate: 10 | 11 | ```bash 12 | ❯ npx @neutrinojs/migrate --help 13 | 14 | migrate [files..] 15 | 16 | Migrate Neutrino middleware to the latest version via codemods 17 | 18 | Positionals: 19 | files files to migrate [default: [".neutrinorc.js"]] 20 | 21 | Options: 22 | --version Show version number [boolean] 23 | --dry, -d dry run (no changes are made to files) [boolean] 24 | --print, -p print transformed files to stdout, useful for development [boolean] 25 | --silent, -s do not write to stdout or stderr [boolean] 26 | --help Show help [boolean] 27 | ``` 28 | 29 | ## Middleware migration 30 | 31 | To convert legacy string and array-based middleware usage in Neutrino middleware 32 | files to function calls: 33 | 34 | ```bash 35 | ❯ npx @neutrinojs/migrate 36 | ``` 37 | 38 | This will make transformations in `.neutrinorc.js` by default. You can manually 39 | specify middleware files to transform by passing them as arguments on the 40 | command line: 41 | 42 | ```bash 43 | ❯ npx @neutrinojs/migrate .neutrinorc.js 44 | ❯ npx @neutrinojs/migrate index.js 45 | ❯ npx @neutrinojs/migrate src/index.js src/other.js .neutrinorc.js 46 | ``` 47 | 48 | This will make the following transformations: 49 | 50 | - Convert string middleware usage in `module.exports.use[]` to function calls: 51 | 52 | ```js 53 | // Before: 54 | module.exports = { 55 | use: ['@neutrinojs/react'], 56 | }; 57 | 58 | // After: 59 | const react = require('@neutrinojs/react'); 60 | 61 | module.exports = { 62 | use: [react()], 63 | }; 64 | ``` 65 | 66 | - Convert array middleware usage in `module.exports.use[]` to function calls, 67 | respecting the options by passing them as arguments to the function call: 68 | 69 | ```js 70 | // Before: 71 | module.exports = { 72 | use: [ 73 | [ 74 | '@neutrinojs/react', 75 | { 76 | html: { 77 | title: 'Migration App', 78 | }, 79 | }, 80 | ], 81 | ], 82 | }; 83 | 84 | // After: 85 | const react = require('@neutrinojs/react'); 86 | 87 | module.exports = { 88 | use: [ 89 | react({ 90 | html: { 91 | title: 'Migration App', 92 | }, 93 | }), 94 | ], 95 | }; 96 | ``` 97 | 98 | - Convert string middleware usage in `neutrino.use()` to function calls, 99 | respecting any additional arguments by passing them to the new function call: 100 | 101 | ```js 102 | // Before: 103 | module.exports = (neutrino) => { 104 | neutrino.use('@neutrinojs/react'); 105 | }; 106 | 107 | // After: 108 | const react = require('@neutrinojs/react'); 109 | 110 | module.exports = (neutrino) => { 111 | neutrino.use(react()); 112 | }; 113 | ``` 114 | 115 | ```js 116 | // Before: 117 | module.exports = (neutrino) => { 118 | neutrino.use('@neutrinojs/react', { 119 | html: { 120 | title: 'Migration App', 121 | }, 122 | }); 123 | }; 124 | 125 | // After: 126 | const react = require('@neutrinojs/react'); 127 | 128 | module.exports = (neutrino) => { 129 | neutrino.use( 130 | react({ 131 | html: { 132 | title: 'Migration App', 133 | }, 134 | }), 135 | ); 136 | }; 137 | ``` 138 | 139 | ## Contributing 140 | 141 | This project is part of the [neutrino](https://github.com/neutrinojs/neutrino) 142 | repository, a monorepo containing all resources for developing Neutrino and its 143 | core presets and middleware. Follow the 144 | [contributing guide](https://neutrinojs.org/contributing/) for details. 145 | 146 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/migrate.svg 147 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/migrate.svg 148 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/migrate 149 | -------------------------------------------------------------------------------- /packages/migrate/bin/migrate.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const yargs = require('yargs'); 4 | const { run } = require('jscodeshift/src/Runner'); 5 | const { resolve } = require('path'); 6 | const { existsSync } = require('fs'); 7 | 8 | const cli = yargs 9 | .scriptName('migrate') 10 | .command( 11 | '$0 [files..]', 12 | 'Migrate Neutrino middleware to the latest version via codemods', 13 | (yargs) => { 14 | yargs.positional('files', { 15 | array: true, 16 | description: 'files to migrate', 17 | default: ['.neutrinorc.js'], 18 | }); 19 | }, 20 | ) 21 | .option('dry', { 22 | alias: 'd', 23 | description: 'dry run (no changes are made to files)', 24 | boolean: true, 25 | }) 26 | .option('print', { 27 | alias: 'p', 28 | description: 'print transformed files to stdout, useful for development', 29 | boolean: true, 30 | }) 31 | .option('silent', { 32 | alias: 's', 33 | description: 'do not write to stdout or stderr', 34 | boolean: true, 35 | }) 36 | .help() 37 | .wrap(null).argv; 38 | 39 | run( 40 | resolve(__dirname, '../transforms/middleware.js'), 41 | cli.files.map((file) => { 42 | const resolved = resolve(process.cwd(), file); 43 | 44 | if (!existsSync(resolved)) { 45 | throw new Error(`Cannot find file '${resolved}'`); 46 | } 47 | 48 | return resolved; 49 | }), 50 | { dry: cli.dry, silent: cli.silent, print: cli.print }, 51 | ).catch((err) => { 52 | console.error(err); 53 | process.exit(1); 54 | }); 55 | -------------------------------------------------------------------------------- /packages/migrate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/migrate", 3 | "version": "9.5.0", 4 | "description": "Migrate Neutrino projects to the latest version via codemods", 5 | "bin": { 6 | "migrate": "./bin/migrate.js" 7 | }, 8 | "files": [ 9 | "bin", 10 | "transforms" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/neutrinojs/neutrino.git", 15 | "directory": "packages/migrate" 16 | }, 17 | "author": "Eli Perelman ", 18 | "license": "MPL-2.0", 19 | "keywords": [ 20 | "neutrino", 21 | "migrate", 22 | "codemod" 23 | ], 24 | "publishConfig": { 25 | "access": "public" 26 | }, 27 | "engines": { 28 | "node": ">=10", 29 | "npm": ">=5.4.0", 30 | "yarn": ">=1.2.1" 31 | }, 32 | "dependencies": { 33 | "camelcase": "^6.2.0", 34 | "jscodeshift": "^0.11.0", 35 | "yargs": "^16.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/migrate/test/fixtures/.neutrinorc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | root: __dirname, 4 | }, 5 | use: [ 6 | (neutrino) => { 7 | neutrino.use('fake-preset'); 8 | }, 9 | process.env.NODE_ENV === 'development' && '@neutrinojs/eslint', 10 | [ 11 | '@neutrinojs/airbnb-base', 12 | { 13 | eslint: { 14 | baseConfig: { 15 | rules: { 16 | semi: 'off', 17 | }, 18 | }, 19 | }, 20 | }, 21 | ], 22 | '@neutrinojs/node', 23 | process.env.NODE_ENV === 'test' && [ 24 | '@neutrinojs/jest', 25 | { 26 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', 27 | }, 28 | ], 29 | (neutrino) => { 30 | neutrino.config.externals(/^[a-z\-0-9]+$/); 31 | neutrino.use('fake-preset', { alpha: 'beta' }); 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /packages/migrate/test/fixtures/.neutrinorc.js.txt: -------------------------------------------------------------------------------- 1 | const eslint = require('@neutrinojs/eslint'); 2 | const airbnbBase = require('@neutrinojs/airbnb-base'); 3 | const node = require('@neutrinojs/node'); 4 | const jest = require('@neutrinojs/jest'); 5 | const fakePreset = require('fake-preset'); 6 | 7 | module.exports = { 8 | options: { 9 | root: __dirname, 10 | }, 11 | use: [ 12 | (neutrino) => { 13 | neutrino.use(fakePreset()); 14 | }, 15 | process.env.NODE_ENV === 'development' && eslint(), 16 | airbnbBase({ 17 | eslint: { 18 | baseConfig: { 19 | rules: { 20 | semi: 'off', 21 | }, 22 | }, 23 | }, 24 | }), 25 | node(), 26 | process.env.NODE_ENV === 'test' && jest({ 27 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', 28 | }), 29 | (neutrino) => { 30 | neutrino.config.externals(/^[a-z\-0-9]+$/); 31 | neutrino.use(fakePreset({ alpha: 'beta' })); 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /packages/migrate/test/migrate_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { execSync } from 'child_process'; 3 | import { readFileSync } from 'fs'; 4 | import { join, resolve } from 'path'; 5 | 6 | const jscodeshift = join(execSync('yarn bin').toString().trim(), 'jscodeshift'); 7 | const fixture = join(__dirname, 'fixtures/.neutrinorc.js'); 8 | const transform = resolve(__dirname, '../transforms/middleware.js'); 9 | const snapshot = readFileSync(join(__dirname, 'fixtures/.neutrinorc.js.txt')) 10 | .toString() 11 | .replace(/\r\n/g, '\n') 12 | .trim(); 13 | 14 | test('performs valid transformation', (t) => { 15 | const output = execSync(`${jscodeshift} ${fixture} -t ${transform} -d -p -s`) 16 | .toString() 17 | .trim(); 18 | 19 | t.is(output, snapshot); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/mocha/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/mocha/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/mocha", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for testing Neutrino projects with Mocha", 5 | "main": "src/index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "mocha" 10 | ], 11 | "author": "Eli Perelman ", 12 | "license": "MPL-2.0", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/neutrinojs/neutrino.git", 16 | "directory": "packages/mocha" 17 | }, 18 | "publishConfig": { 19 | "access": "public" 20 | }, 21 | "engines": { 22 | "node": ">=10", 23 | "npm": ">=5.4.0", 24 | "yarn": ">=1.2.1" 25 | }, 26 | "dependencies": { 27 | "@babel/core": "^7.12.10", 28 | "@babel/plugin-transform-modules-commonjs": "^7.12.1", 29 | "@babel/register": "^7.12.10", 30 | "babel-merge": "^3.0.0", 31 | "deepmerge": "^1.5.2", 32 | "lodash.omit": "^4.5.0" 33 | }, 34 | "peerDependencies": { 35 | "mocha": "^6.0.0 || ^7.0.0 || ^8.0.0", 36 | "neutrino": "^9.0.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/mocha/src/index.js: -------------------------------------------------------------------------------- 1 | const babelMerge = require('babel-merge'); 2 | const merge = require('deepmerge'); 3 | const omit = require('lodash.omit'); 4 | 5 | module.exports = 6 | (opts = {}) => 7 | (neutrino) => { 8 | const lintRule = neutrino.config.module.rules.get('lint'); 9 | 10 | if (lintRule) { 11 | lintRule.use('eslint').tap( 12 | // Don't adjust the lint configuration for projects using their own .eslintrc. 13 | (lintOptions) => 14 | lintOptions.useEslintrc 15 | ? lintOptions 16 | : merge(lintOptions, { 17 | baseConfig: { 18 | env: { 19 | mocha: true, 20 | }, 21 | }, 22 | }), 23 | ); 24 | } 25 | 26 | neutrino.register('mocha', (neutrino) => { 27 | const { extensions } = neutrino.options; 28 | const baseOptions = neutrino.config.module.rules.has('compile') 29 | ? neutrino.config.module.rule('compile').use('babel').get('options') 30 | : {}; 31 | const babelOptions = omit( 32 | babelMerge(baseOptions, { 33 | extensions: extensions.map((ext) => `.${ext}`), 34 | plugins: [ 35 | require.resolve('@babel/plugin-transform-modules-commonjs'), 36 | ], 37 | }), 38 | ['cacheDirectory'], 39 | ); 40 | 41 | process.env.MOCHA_BABEL_OPTIONS = JSON.stringify(babelOptions); 42 | 43 | return merge( 44 | { 45 | require: require.resolve('./register'), 46 | recursive: true, 47 | extension: extensions, 48 | }, 49 | opts, 50 | ); 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /packages/mocha/src/register.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')(JSON.parse(process.env.MOCHA_BABEL_OPTIONS)); 2 | -------------------------------------------------------------------------------- /packages/mocha/test/mocha_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import lint from '../../eslint'; 3 | import Neutrino from '../../neutrino/Neutrino'; 4 | import neutrino from '../../neutrino'; 5 | 6 | const mw = (...args) => require('..')(...args); 7 | const originalNodeEnv = process.env.NODE_ENV; 8 | 9 | test.afterEach(() => { 10 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 11 | process.env.NODE_ENV = originalNodeEnv; 12 | }); 13 | 14 | test('loads middleware', (t) => { 15 | t.notThrows(() => require('..')); 16 | }); 17 | 18 | test('uses middleware', (t) => { 19 | t.notThrows(() => { 20 | const api = new Neutrino(); 21 | api.use(mw()); 22 | }); 23 | }); 24 | 25 | test('instantiates', (t) => { 26 | const api = new Neutrino(); 27 | api.use(mw()); 28 | 29 | t.notThrows(() => api.config.toConfig()); 30 | }); 31 | 32 | test('instantiates in development', (t) => { 33 | process.env.NODE_ENV = 'development'; 34 | const api = new Neutrino(); 35 | api.use(mw()); 36 | 37 | t.notThrows(() => api.config.toConfig()); 38 | }); 39 | 40 | test('instantiates in production', (t) => { 41 | process.env.NODE_ENV = 'production'; 42 | const api = new Neutrino(); 43 | api.use(mw()); 44 | 45 | t.notThrows(() => api.config.toConfig()); 46 | }); 47 | 48 | test('exposes mocha output handler', (t) => { 49 | const api = new Neutrino(); 50 | api.use(mw()); 51 | 52 | const handler = api.outputHandlers.get('mocha'); 53 | 54 | t.is(typeof handler, 'function'); 55 | }); 56 | 57 | test('exposes mocha method', (t) => { 58 | t.is(typeof neutrino(mw()).mocha, 'function'); 59 | }); 60 | 61 | test('updates lint config by default', (t) => { 62 | const api = new Neutrino(); 63 | api.use(lint()); 64 | api.use(mw()); 65 | const options = api.config.module.rule('lint').use('eslint').get('options'); 66 | t.deepEqual(options.baseConfig.env, { 67 | es6: true, 68 | mocha: true, 69 | }); 70 | }); 71 | 72 | test('does not update lint config if useEslintrc true', (t) => { 73 | const api = new Neutrino(); 74 | api.use(lint({ eslint: { useEslintrc: true } })); 75 | api.use(mw()); 76 | const options = api.config.module.rule('lint').use('eslint').get('options'); 77 | t.deepEqual(options.baseConfig, {}); 78 | }); 79 | -------------------------------------------------------------------------------- /packages/neutrino/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/neutrino/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | ### Create and build modern JavaScript applications with zero initial configuration 4 | 5 | #### Neutrino combines the power of webpack with the simplicity of presets. 6 | 7 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 8 | 9 | --- 10 | 11 | Neutrino is a configuration management tool for the webpack ecosystem that 12 | supports building, testing, linting, and developing JavaScript projects based on 13 | shared configuration presets and middleware. You can use Neutrino within your 14 | project alongside webpack, ESLint, Jest, Karma, and more of your favorite CLI 15 | tools. It intends to make the process of initializing and building projects much 16 | simpler by providing minimal development dependencies and tightening the 17 | integration between tools. 18 | 19 | Neutrino supports webpack for building both web and Node.js projects by 20 | providing complete build presets which can be shared across targets and 21 | projects. You can use Neutrino base presets to get started building a variety of 22 | projects, and you can create your own presets by extending the Neutrino core 23 | ones to be shared across your own projects or even by the community. Presets can 24 | even be manipulated on a project-by-project basis to handle almost any build 25 | situation your preset doesn't cover. 26 | 27 | ## Documentation 28 | 29 | See the [Neutrino docs](https://neutrinojs.org/) for details on installation, 30 | getting started, usage, and customizing. 31 | 32 | [npm-image]: https://img.shields.io/npm/v/neutrino.svg 33 | [npm-downloads]: https://img.shields.io/npm/dt/neutrino.svg 34 | [npm-url]: https://www.npmjs.com/package/neutrino 35 | -------------------------------------------------------------------------------- /packages/neutrino/bin/neutrino.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const yargsParser = require('yargs-parser'); 4 | const { join } = require('path'); 5 | const neutrino = require('..'); 6 | 7 | const argv = yargsParser(process.argv.slice(2)); 8 | 9 | if (argv.inspect) { 10 | if (argv.config) { 11 | // eslint-disable-next-line global-require, import/no-dynamic-require 12 | const middleware = require(join(process.cwd(), argv.config)); 13 | neutrino(middleware).inspect(); 14 | process.exit(); 15 | } 16 | neutrino().inspect(); 17 | process.exit(); 18 | } 19 | 20 | console.error(` 21 | The "neutrino start/build/lint/test" commands were removed in Neutrino 9. 22 | Please see the migration guide for how to upgrade your project: 23 | https://neutrinojs.org/migration-guide/ 24 | 25 | You may still inspect the generated webpack configuration using: 26 | neutrino --inspect --mode {production,development} 27 | or inspect with custom config 28 | neutrino --inspect --mode {production,development} --config .custom.neutrino.config 29 | `); 30 | 31 | process.exit(1); 32 | -------------------------------------------------------------------------------- /packages/neutrino/errors.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-classes-per-file */ 2 | 3 | class ConfigurationError extends Error { 4 | get name() { 5 | return this.constructor.name; 6 | } 7 | } 8 | 9 | class DuplicateRuleError extends ConfigurationError { 10 | constructor(middlewareName, ruleId) { 11 | super( 12 | `${middlewareName} has been used twice with the same ruleId of '${ruleId}', ` + 13 | 'which would overwrite the existing configuration. If you are including ' + 14 | 'this preset manually to customise rules configured by another preset, ' + 15 | "instead use that preset's own options to do so.", 16 | ); 17 | } 18 | } 19 | 20 | module.exports = { 21 | ConfigurationError, 22 | DuplicateRuleError, 23 | }; 24 | -------------------------------------------------------------------------------- /packages/neutrino/extensions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // The list of source extensions here needs to be kept in sync with the 3 | // extension list consumed create-project's lint script definition. 4 | // Modifying a value here should have an accompanying change there as well. 5 | // We can't pull in neutrino there as that would potentially give us 6 | // conflicting versions in node_modules. 7 | source: ['mjs', 'jsx', 'js'], 8 | style: ['css', 'less', 'sass', 'scss'], 9 | media: [ 10 | 'jpg', 11 | 'jpeg', 12 | 'png', 13 | 'gif', 14 | 'eot', 15 | 'otf', 16 | 'webp', 17 | 'svg', 18 | 'ttf', 19 | 'woff', 20 | 'woff2', 21 | 'mp4', 22 | 'webm', 23 | 'wav', 24 | 'mp3', 25 | 'm4a', 26 | 'aac', 27 | 'oga', 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /packages/neutrino/handlers.js: -------------------------------------------------------------------------------- 1 | const { ConfigurationError } = require('./errors'); 2 | 3 | const webpack = (neutrino) => { 4 | if (neutrino.config.entryPoints.has('vendor')) { 5 | throw new ConfigurationError( 6 | 'Vendor chunks are now automatically generated. ' + 7 | 'Remove the manual `vendor` entrypoint.', 8 | ); 9 | } 10 | 11 | return neutrino.config.toConfig(); 12 | }; 13 | 14 | const inspect = (neutrino) => { 15 | const stringifiedConfig = neutrino.config.toString({ 16 | configPrefix: 'neutrino.config', 17 | verbose: true, 18 | }); 19 | console.log(stringifiedConfig); 20 | }; 21 | 22 | module.exports = { 23 | webpack, 24 | inspect, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/neutrino/index.js: -------------------------------------------------------------------------------- 1 | const yargsParser = require('yargs-parser'); 2 | const { join } = require('path'); 3 | const Neutrino = require('./Neutrino'); 4 | const { webpack, inspect } = require('./handlers'); 5 | const { ConfigurationError } = require('./errors'); 6 | 7 | const extractMiddlewareAndOptions = (format) => 8 | typeof format === 'function' ? { ...format, use: format } : { ...format }; 9 | 10 | module.exports = ( 11 | // eslint-disable-next-line global-require, import/no-dynamic-require 12 | middleware = require(join(process.cwd(), '.neutrinorc.js')), 13 | ) => { 14 | const { use, options, env } = extractMiddlewareAndOptions(middleware); 15 | 16 | if (env) { 17 | throw new ConfigurationError( 18 | 'Specifying "env" in middleware has been removed.' + 19 | 'Apply middleware conditionally instead.', 20 | ); 21 | } 22 | 23 | const neutrino = new Neutrino(options); 24 | let { mode } = yargsParser(process.argv.slice(2)); 25 | 26 | if (mode) { 27 | // If specified, --mode takes priority and overrides any existing NODE_ENV. 28 | process.env.NODE_ENV = mode; 29 | } else if (process.env.NODE_ENV) { 30 | // Development mode is most appropriate for a !production NODE_ENV (such as `NODE_ENV=test`). 31 | mode = process.env.NODE_ENV === 'production' ? 'production' : 'development'; 32 | } else { 33 | // Default NODE_ENV to the more strict value, to save needing to do so in .eslintrc.js. 34 | // However don't set `mode` since webpack already defaults it to `production`, and in so 35 | // doing outputs a useful message informing users that they are relying on the defaults. 36 | process.env.NODE_ENV = 'production'; 37 | } 38 | 39 | if (mode) { 40 | neutrino.config.mode(mode); 41 | } 42 | 43 | neutrino.register('webpack', webpack); 44 | neutrino.register('inspect', inspect); 45 | 46 | if (use) { 47 | try { 48 | if (Array.isArray(use)) { 49 | use.forEach((use) => neutrino.use(use)); 50 | } else { 51 | neutrino.use(use); 52 | } 53 | } catch (err) { 54 | console.error( 55 | '\nAn error occurred when loading the Neutrino configuration.\n', 56 | ); 57 | console.error(err); 58 | process.exit(1); 59 | } 60 | } 61 | 62 | const adapter = { 63 | output(name) { 64 | const handler = neutrino.outputHandlers.get(name); 65 | 66 | if (!handler) { 67 | throw new Error(`Unable to find an output handler named "${name}"`); 68 | } 69 | 70 | return handler(neutrino); 71 | }, 72 | }; 73 | 74 | return new Proxy(adapter, { 75 | get(object, property) { 76 | return property === 'output' 77 | ? Reflect.get(object, property) 78 | : Reflect.get(object, 'output').bind(object, property); 79 | }, 80 | }); 81 | }; 82 | -------------------------------------------------------------------------------- /packages/neutrino/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neutrino", 3 | "version": "9.5.0", 4 | "description": "Create and build JS applications with managed configurations", 5 | "main": "index.js", 6 | "bin": { 7 | "neutrino": "bin/neutrino.js" 8 | }, 9 | "keywords": [ 10 | "neutrino", 11 | "webpack", 12 | "babel" 13 | ], 14 | "author": "Eli Perelman ", 15 | "license": "MPL-2.0", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/neutrinojs/neutrino.git", 19 | "directory": "packages/neutrino" 20 | }, 21 | "homepage": "https://neutrinojs.org", 22 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 23 | "scripts": { 24 | "test": "ava test" 25 | }, 26 | "engines": { 27 | "node": ">=10", 28 | "npm": ">=5.4.0", 29 | "yarn": ">=1.2.1" 30 | }, 31 | "dependencies": { 32 | "lodash.clonedeep": "^4.5.0", 33 | "semver": "^7.3.4", 34 | "webpack-chain": "^6.5.1", 35 | "yargs-parser": "^20.2.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/neutrino/test/fixtures/middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => 2 | api.config.module.rule('compile').test(api.regexFromExtensions(['js'])); 3 | -------------------------------------------------------------------------------- /packages/neutrino/test/fixtures/test-module/errorMiddleware.js: -------------------------------------------------------------------------------- 1 | [; 2 | -------------------------------------------------------------------------------- /packages/neutrino/test/fixtures/test-module/middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = () => 'root'; 2 | -------------------------------------------------------------------------------- /packages/neutrino/test/fixtures/test-module/node_modules/alpha/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => "alpha" 2 | -------------------------------------------------------------------------------- /packages/neutrino/test/package_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import neutrino from '..'; 3 | 4 | const originalNodeEnv = process.env.NODE_ENV; 5 | 6 | test.afterEach(() => { 7 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 8 | process.env.NODE_ENV = originalNodeEnv; 9 | }); 10 | 11 | test('default mode derived from production NODE_ENV', (t) => { 12 | process.env.NODE_ENV = 'production'; 13 | const webpackConfig = neutrino().output('webpack'); 14 | t.is(webpackConfig.mode, 'production'); 15 | }); 16 | 17 | test('default mode derived from development NODE_ENV', (t) => { 18 | process.env.NODE_ENV = 'development'; 19 | const webpackConfig = neutrino().output('webpack'); 20 | t.is(webpackConfig.mode, 'development'); 21 | }); 22 | 23 | test('default mode derived from test NODE_ENV', (t) => { 24 | process.env.NODE_ENV = 'test'; 25 | const webpackConfig = neutrino().output('webpack'); 26 | t.is(webpackConfig.mode, 'development'); 27 | }); 28 | 29 | test('undefined mode and NODE_ENV sets only NODE_ENV', (t) => { 30 | delete process.env.NODE_ENV; 31 | const webpackConfig = neutrino().output('webpack'); 32 | t.is(process.env.NODE_ENV, 'production'); 33 | t.false('mode' in webpackConfig); 34 | }); 35 | 36 | test('throws when vendor entrypoint defined', (t) => { 37 | const mw = (neutrino) => neutrino.config.entry('vendor').add('lodash'); 38 | t.throws( 39 | () => neutrino(mw).output('webpack'), 40 | /Remove the manual `vendor` entrypoint/, 41 | ); 42 | }); 43 | 44 | test('throws when trying to use a non-registered output', (t) => { 45 | t.throws( 46 | () => neutrino(Function.prototype).output('fake'), 47 | 'Unable to find an output handler named "fake"', 48 | ); 49 | }); 50 | 51 | test('throws when trying to use a non-registered proxied method', (t) => { 52 | t.throws( 53 | () => neutrino(Function.prototype).fake(), 54 | 'Unable to find an output handler named "fake"', 55 | ); 56 | }); 57 | 58 | test('throws when trying to specify "env"', (t) => { 59 | t.throws( 60 | () => neutrino({ env: {} }), 61 | /Specifying "env" in middleware has been removed/, 62 | ); 63 | }); 64 | 65 | test('exposes webpack output handler', (t) => { 66 | t.notThrows(() => neutrino(Function.prototype).output('webpack')); 67 | }); 68 | 69 | test('exposes webpack config from output', (t) => { 70 | const handler = neutrino(Function.prototype).output('webpack'); 71 | t.is(typeof handler, 'object'); 72 | }); 73 | 74 | test('exposes webpack method', (t) => { 75 | t.is(typeof neutrino(Function.prototype).webpack, 'function'); 76 | }); 77 | 78 | test('exposes webpack config from method', (t) => { 79 | const handler = neutrino(Function.prototype).webpack(); 80 | t.is(typeof handler, 'object'); 81 | }); 82 | 83 | test('exposes inspect output handler', (t) => { 84 | t.notThrows(() => { 85 | // Overriding console.log to prevent the inspect() method from logging to 86 | // the console during tests, interfering with the ava output. 87 | const original = console.log; 88 | 89 | console.log = Function.prototype; 90 | neutrino(Function.prototype).output('inspect'); 91 | console.log = original.bind(console); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /packages/node/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/node", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building Node.js projects", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "node.js", 10 | "node" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/node" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "@babel/core": "^7.12.10", 31 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 32 | "@babel/preset-env": "^7.12.11", 33 | "@neutrinojs/banner": "9.5.0", 34 | "@neutrinojs/clean": "9.5.0", 35 | "@neutrinojs/compile-loader": "9.5.0", 36 | "@neutrinojs/start-server": "9.5.0", 37 | "babel-merge": "^3.0.0", 38 | "deepmerge": "^1.5.2", 39 | "lodash.omit": "^4.5.0", 40 | "webpack-node-externals": "^1.7.2" 41 | }, 42 | "peerDependencies": { 43 | "neutrino": "^9.0.0", 44 | "webpack": "^4.0.0", 45 | "webpack-cli": "^3.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/node/test/node_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { validate } from 'webpack'; 3 | import Neutrino from '../../neutrino/Neutrino'; 4 | 5 | const mw = (...args) => require('..')(...args); 6 | const expectedExtensions = ['.wasm', '.mjs', '.jsx', '.js', '.json']; 7 | const originalNodeEnv = process.env.NODE_ENV; 8 | 9 | test.afterEach(() => { 10 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 11 | process.env.NODE_ENV = originalNodeEnv; 12 | }); 13 | 14 | test('loads preset', (t) => { 15 | t.notThrows(() => require('..')); 16 | }); 17 | 18 | test('uses preset', (t) => { 19 | const api = new Neutrino(); 20 | 21 | t.notThrows(() => api.use(mw())); 22 | }); 23 | 24 | test('uses preset with custom main', (t) => { 25 | const api = new Neutrino({ mains: { server: 'server' } }); 26 | 27 | t.notThrows(() => api.use(mw())); 28 | t.true(api.config.entryPoints.has('server')); 29 | }); 30 | 31 | test('valid preset production', (t) => { 32 | process.env.NODE_ENV = 'production'; 33 | const api = new Neutrino(); 34 | api.use(mw()); 35 | const config = api.config.toConfig(); 36 | 37 | // Common 38 | t.is(config.target, 'node'); 39 | t.deepEqual(config.resolve.extensions, expectedExtensions); 40 | t.is(config.optimization, undefined); 41 | t.is(config.devServer, undefined); 42 | t.deepEqual(config.stats, { 43 | children: false, 44 | entrypoints: false, 45 | modules: false, 46 | }); 47 | 48 | // NODE_ENV/command specific 49 | t.is(config.devtool, 'source-map'); 50 | 51 | const errors = validate(config); 52 | t.is(errors.length, 0); 53 | }); 54 | 55 | test('valid preset development', (t) => { 56 | process.env.NODE_ENV = 'development'; 57 | const api = new Neutrino(); 58 | api.use(mw()); 59 | const config = api.config.toConfig(); 60 | 61 | // Common 62 | t.is(config.target, 'node'); 63 | t.deepEqual(config.resolve.extensions, expectedExtensions); 64 | t.is(config.optimization, undefined); 65 | t.is(config.devServer, undefined); 66 | t.deepEqual(config.stats, { 67 | children: false, 68 | entrypoints: false, 69 | modules: false, 70 | }); 71 | 72 | // NODE_ENV/command specific 73 | t.is(config.devtool, 'inline-sourcemap'); 74 | 75 | const errors = validate(config); 76 | t.is(errors.length, 0); 77 | }); 78 | 79 | test('throws when polyfills defined', (t) => { 80 | const api = new Neutrino(); 81 | t.throws( 82 | () => api.use(mw({ polyfills: {} })), 83 | /The polyfills option has been removed/, 84 | ); 85 | }); 86 | -------------------------------------------------------------------------------- /packages/preact/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/preact/index.js: -------------------------------------------------------------------------------- 1 | const babelMerge = require('babel-merge'); 2 | const web = require('@neutrinojs/web'); 3 | const merge = require('deepmerge'); 4 | 5 | module.exports = 6 | (opts = {}) => 7 | (neutrino) => { 8 | const options = { 9 | hot: true, 10 | ...opts, 11 | babel: babelMerge( 12 | { 13 | plugins: [ 14 | [ 15 | require.resolve('@babel/plugin-transform-react-jsx'), 16 | { pragma: 'h', pragmaFrag: 'Fragment' }, 17 | ], 18 | ], 19 | }, 20 | opts.babel || {}, 21 | ), 22 | }; 23 | 24 | neutrino.use(web(options)); 25 | 26 | neutrino.config.resolve.alias 27 | .set('react', 'preact/compat') 28 | .set('react-dom/test-utils', 'preact/test-utils') 29 | // Must be after test-utils 30 | .set('react-dom', 'preact/compat'); 31 | 32 | const lintRule = neutrino.config.module.rules.get('lint'); 33 | if (lintRule) { 34 | lintRule.use('eslint').tap( 35 | // Don't adjust the lint configuration for projects using their own .eslintrc. 36 | (lintOptions) => 37 | lintOptions.useEslintrc 38 | ? lintOptions 39 | : merge(lintOptions, { 40 | baseConfig: { 41 | plugins: ['react'], 42 | settings: { 43 | react: { 44 | pragma: 'h', 45 | }, 46 | }, 47 | }, 48 | }), 49 | ); 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /packages/preact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/preact", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building Preact web applications", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "preact", 10 | "web", 11 | "hot module reload" 12 | ], 13 | "author": "Fahad Hossain <8bit.demoncoder@gmail.com>", 14 | "license": "MPL-2.0", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/preact" 19 | }, 20 | "homepage": "https://neutrinojs.org", 21 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "engines": { 26 | "node": ">=10", 27 | "npm": ">=5.4.0", 28 | "yarn": ">=1.2.1" 29 | }, 30 | "dependencies": { 31 | "@babel/core": "^7.12.10", 32 | "@babel/plugin-transform-react-jsx": "^7.12.12", 33 | "@neutrinojs/web": "9.5.0", 34 | "babel-merge": "^3.0.0", 35 | "deepmerge": "^1.5.2", 36 | "eslint-plugin-react": "^7.21.5" 37 | }, 38 | "devDependencies": { 39 | "preact": "^10.5.7" 40 | }, 41 | "peerDependencies": { 42 | "neutrino": "^9.0.0", 43 | "webpack": "^4.0.0", 44 | "webpack-cli": "^3.0.0", 45 | "webpack-dev-server": "^3.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/preact/test/preact_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { validate } from 'webpack'; 3 | import lint from '../../eslint'; 4 | import Neutrino from '../../neutrino/Neutrino'; 5 | 6 | const mw = (...args) => require('..')(...args); 7 | const originalNodeEnv = process.env.NODE_ENV; 8 | 9 | test.afterEach(() => { 10 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 11 | process.env.NODE_ENV = originalNodeEnv; 12 | }); 13 | 14 | test('loads preset', (t) => { 15 | t.notThrows(() => require('..')); 16 | }); 17 | 18 | test('uses preset', (t) => { 19 | t.notThrows(() => new Neutrino().use(mw())); 20 | }); 21 | 22 | test('valid preset production', (t) => { 23 | process.env.NODE_ENV = 'production'; 24 | const api = new Neutrino(); 25 | api.use(mw()); 26 | 27 | const errors = validate(api.config.toConfig()); 28 | 29 | t.is(errors.length, 0); 30 | }); 31 | 32 | test('valid preset development', (t) => { 33 | process.env.NODE_ENV = 'development'; 34 | const api = new Neutrino(); 35 | api.use(mw()); 36 | 37 | const errors = validate(api.config.toConfig()); 38 | 39 | t.is(errors.length, 0); 40 | }); 41 | 42 | test('updates lint config by default', (t) => { 43 | const api = new Neutrino(); 44 | api.use(lint()); 45 | api.use(mw()); 46 | const options = api.config.module.rule('lint').use('eslint').get('options'); 47 | t.deepEqual(options.baseConfig.env, { 48 | browser: true, 49 | commonjs: true, 50 | es6: true, 51 | }); 52 | t.deepEqual(options.baseConfig.plugins, ['babel', 'react']); 53 | t.deepEqual(options.baseConfig.settings, { react: { pragma: 'h' } }); 54 | }); 55 | 56 | test('does not update lint config if useEslintrc true', (t) => { 57 | const api = new Neutrino(); 58 | api.use(lint({ eslint: { useEslintrc: true } })); 59 | api.use(mw()); 60 | const options = api.config.module.rule('lint').use('eslint').get('options'); 61 | t.deepEqual(options.baseConfig, {}); 62 | }); 63 | -------------------------------------------------------------------------------- /packages/react-components/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/react-components/index.js: -------------------------------------------------------------------------------- 1 | const react = require('@neutrinojs/react'); 2 | const banner = require('@neutrinojs/banner'); 3 | const merge = require('deepmerge'); 4 | const nodeExternals = require('webpack-node-externals'); 5 | const { extname, join, basename } = require('path'); 6 | const { readdirSync } = require('fs'); 7 | 8 | module.exports = 9 | (opts = {}) => 10 | (neutrino) => { 11 | const options = merge( 12 | { 13 | html: process.env.NODE_ENV === 'development' && { 14 | title: 'React Preview', 15 | }, 16 | externals: opts.externals !== false && {}, 17 | style: { 18 | extract: { 19 | plugin: { 20 | // Override the @neutrinojs/react production behaviour of hashed CSS 21 | // filenames, and output to the build root, not an `assets/` subdirectory. 22 | filename: '[name].css', 23 | }, 24 | }, 25 | }, 26 | devtool: { 27 | production: 'source-map', 28 | }, 29 | targets: { browsers: 'ie 9' }, 30 | }, 31 | opts, 32 | ); 33 | 34 | neutrino.config.when( 35 | process.env.NODE_ENV === 'development', 36 | () => { 37 | neutrino.use(react(options)); 38 | }, 39 | () => { 40 | const components = join( 41 | neutrino.options.source, 42 | options.components || 'components', 43 | ); 44 | 45 | Object.keys(neutrino.options.mains).forEach((key) => { 46 | delete neutrino.options.mains[key]; // eslint-disable-line no-param-reassign 47 | }); 48 | 49 | readdirSync(components).forEach((component) => { 50 | // eslint-disable-next-line no-param-reassign 51 | neutrino.options.mains[basename(component, extname(component))] = { 52 | entry: join(components, component), 53 | }; 54 | }); 55 | 56 | const pkg = neutrino.options.packageJson || {}; 57 | const hasSourceMap = 58 | (pkg.dependencies && 'source-map-support' in pkg.dependencies) || 59 | (pkg.devDependencies && 'source-map-support' in pkg.devDependencies); 60 | 61 | neutrino.use(react(options)); 62 | 63 | neutrino.config 64 | .when(options.externals, (config) => 65 | config.externals([nodeExternals(options.externals)]), 66 | ) 67 | .when(hasSourceMap, () => neutrino.use(banner())) 68 | // Disable the chunking behaviour inherited from the react preset 69 | .optimization.splitChunks(false) 70 | .runtimeChunk(false) 71 | .end() 72 | .output // Override hashed filename/subdirectory usage inherited from @neutrinojs/react. 73 | .filename('[name].js') 74 | .library('[name]') 75 | .libraryTarget('umd') 76 | .umdNamedDefine(true); 77 | }, 78 | ); 79 | }; 80 | -------------------------------------------------------------------------------- /packages/react-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/react-components", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building sets of React components", 5 | "main": "index.js", 6 | "files": [ 7 | "lib", 8 | "src", 9 | "index.js" 10 | ], 11 | "author": "Eli Perelman ", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/neutrinojs/neutrino.git", 15 | "directory": "packages/react-components" 16 | }, 17 | "license": "MPL-2.0", 18 | "publishConfig": { 19 | "access": "public" 20 | }, 21 | "engines": { 22 | "node": ">=10", 23 | "npm": ">=5.4.0", 24 | "yarn": ">=1.2.1" 25 | }, 26 | "dependencies": { 27 | "@neutrinojs/banner": "9.5.0", 28 | "@neutrinojs/react": "9.5.0", 29 | "deepmerge": "^1.5.2", 30 | "webpack-node-externals": "^1.7.2" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0", 35 | "webpack-cli": "^3.0.0", 36 | "webpack-dev-server": "^3.0.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/react-components/test/components_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { validate } from 'webpack'; 3 | import Neutrino from '../../neutrino/Neutrino'; 4 | 5 | const mw = (...args) => require('..')(...args); 6 | const originalNodeEnv = process.env.NODE_ENV; 7 | 8 | test.afterEach(() => { 9 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 10 | process.env.NODE_ENV = originalNodeEnv; 11 | }); 12 | 13 | test('loads preset', (t) => { 14 | t.notThrows(() => require('..')); 15 | }); 16 | 17 | test('uses preset', (t) => { 18 | const api = new Neutrino({ root: __dirname }); 19 | 20 | t.notThrows(() => api.use(mw({ name: 'alpha' }))); 21 | }); 22 | 23 | test('valid preset production', (t) => { 24 | process.env.NODE_ENV = 'production'; 25 | const api = new Neutrino({ root: __dirname }); 26 | 27 | api.use(mw()); 28 | const config = api.config.toConfig(); 29 | 30 | // Common 31 | t.is(config.target, 'web'); 32 | t.is(config.optimization.runtimeChunk, false); 33 | t.is(config.optimization.splitChunks, false); 34 | 35 | // NODE_ENV/command specific 36 | t.true(config.optimization.minimize); 37 | t.is(config.devtool, 'source-map'); 38 | t.is(config.devServer, undefined); 39 | 40 | const errors = validate(config); 41 | t.is(errors.length, 0); 42 | }); 43 | 44 | test('valid preset development', (t) => { 45 | process.env.NODE_ENV = 'development'; 46 | const api = new Neutrino({ root: __dirname }); 47 | 48 | api.use(mw()); 49 | const config = api.config.toConfig(); 50 | 51 | // Common 52 | t.is(config.target, 'web'); 53 | t.is(config.optimization.runtimeChunk, 'single'); 54 | t.is(config.optimization.splitChunks.chunks, 'all'); 55 | 56 | const errors = validate(config); 57 | t.is(errors.length, 0); 58 | }); 59 | -------------------------------------------------------------------------------- /packages/react-components/test/src/components/Empty.jsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neutrinojs/neutrino/f9d476446983684225545159f58bbed2a93ca824/packages/react-components/test/src/components/Empty.jsx -------------------------------------------------------------------------------- /packages/react/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/react/index.js: -------------------------------------------------------------------------------- 1 | const web = require('@neutrinojs/web'); 2 | const babelMerge = require('babel-merge'); 3 | const merge = require('deepmerge'); 4 | 5 | module.exports = 6 | (opts = {}) => 7 | (neutrino) => { 8 | const options = merge( 9 | { 10 | hot: true, 11 | babel: {}, 12 | }, 13 | opts, 14 | ); 15 | let reactHotLoader = false; 16 | 17 | try { 18 | // Attempt to load react-hot-loader from the user's installation. 19 | reactHotLoader = require.resolve('react-hot-loader/babel'); 20 | } catch (err) {} // eslint-disable-line no-empty 21 | 22 | Object.assign(options, { 23 | babel: babelMerge( 24 | { 25 | plugins: [ 26 | // The RHL plugin is enabled in production too since it removes the `hot(module)(...)` 27 | // wrapper, allowing webpack to use its concatenate modules optimization. 28 | options.hot && reactHotLoader, 29 | process.env.NODE_ENV === 'production' && [ 30 | require.resolve('babel-plugin-transform-react-remove-prop-types'), 31 | { 32 | removeImport: true, 33 | }, 34 | ], 35 | ].filter(Boolean), 36 | presets: [ 37 | [ 38 | require.resolve('@babel/preset-react'), 39 | { 40 | // Enable development helpers both in development and testing. 41 | development: process.env.NODE_ENV !== 'production', 42 | // When spreading props, use inline object with spread elements directly instead of 43 | // Babel's extend helper or Object.assign. @babel/env will still transpile these down 44 | // if required for the target browsers. 45 | useSpread: true, 46 | }, 47 | ], 48 | ], 49 | }, 50 | options.babel, 51 | ), 52 | }); 53 | 54 | neutrino.use(web(options)); 55 | 56 | const lintRule = neutrino.config.module.rules.get('lint'); 57 | if (lintRule) { 58 | lintRule.use('eslint').tap( 59 | // Don't adjust the lint configuration for projects using their own .eslintrc. 60 | (lintOptions) => 61 | lintOptions.useEslintrc 62 | ? lintOptions 63 | : merge(lintOptions, { 64 | baseConfig: { 65 | plugins: ['react', 'react-hooks'], 66 | rules: { 67 | // Enforces the rules of hooks: 68 | // https://reactjs.org/docs/hooks-rules.html 69 | 'react-hooks/rules-of-hooks': 'error', 70 | 'react-hooks/exhaustive-deps': 'warn', 71 | }, 72 | settings: { 73 | react: { 74 | version: 'detect', 75 | }, 76 | }, 77 | }, 78 | }), 79 | ); 80 | } 81 | 82 | neutrino.config.resolve.alias 83 | .set('react-native', 'react-native-web') 84 | .end() 85 | .extensions.prepend('.web.js') 86 | .prepend('.web.jsx'); 87 | }; 88 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/react", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building React web applications", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "react", 10 | "web", 11 | "hot module replacement" 12 | ], 13 | "author": "Eli Perelman ", 14 | "license": "MPL-2.0", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/react" 19 | }, 20 | "homepage": "https://neutrinojs.org", 21 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "engines": { 26 | "node": ">=10", 27 | "npm": ">=5.4.0", 28 | "yarn": ">=1.2.1" 29 | }, 30 | "dependencies": { 31 | "@babel/core": "^7.12.10", 32 | "@babel/preset-react": "^7.12.10", 33 | "@neutrinojs/web": "9.5.0", 34 | "babel-merge": "^3.0.0", 35 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24", 36 | "deepmerge": "^1.5.2", 37 | "eslint-plugin-react": "^7.21.5", 38 | "eslint-plugin-react-hooks": "^4.2.0" 39 | }, 40 | "devDependencies": { 41 | "react": "^16.14.0", 42 | "react-dom": "^16.14.0", 43 | "react-hot-loader": "^4.13.0" 44 | }, 45 | "peerDependencies": { 46 | "neutrino": "^9.0.0", 47 | "webpack": "^4.0.0", 48 | "webpack-cli": "^3.0.0", 49 | "webpack-dev-server": "^3.0.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/react/test/react_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { validate } from 'webpack'; 3 | import lint from '../../eslint'; 4 | import Neutrino from '../../neutrino/Neutrino'; 5 | 6 | const mw = (...args) => require('..')(...args); 7 | const newExtensions = ['.web.jsx', '.web.js']; 8 | const originalNodeEnv = process.env.NODE_ENV; 9 | 10 | test.afterEach(() => { 11 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 12 | process.env.NODE_ENV = originalNodeEnv; 13 | }); 14 | 15 | test('loads preset', (t) => { 16 | t.notThrows(() => require('..')); 17 | }); 18 | 19 | test('uses preset', (t) => { 20 | t.notThrows(() => new Neutrino().use(mw())); 21 | }); 22 | 23 | test('valid preset production', (t) => { 24 | process.env.NODE_ENV = 'production'; 25 | const api = new Neutrino(); 26 | api.use(mw()); 27 | const config = api.config.toConfig(); 28 | 29 | // Common 30 | t.deepEqual( 31 | config.resolve.extensions.slice(0, newExtensions.length), 32 | newExtensions, 33 | ); 34 | 35 | const errors = validate(config); 36 | t.is(errors.length, 0); 37 | }); 38 | 39 | test('valid preset development', (t) => { 40 | process.env.NODE_ENV = 'development'; 41 | const api = new Neutrino(); 42 | api.use(mw()); 43 | const config = api.config.toConfig(); 44 | 45 | // Common 46 | t.deepEqual( 47 | config.resolve.extensions.slice(0, newExtensions.length), 48 | newExtensions, 49 | ); 50 | 51 | const errors = validate(config); 52 | t.is(errors.length, 0); 53 | }); 54 | 55 | test('valid preset test', (t) => { 56 | process.env.NODE_ENV = 'test'; 57 | const api = new Neutrino(); 58 | api.use(mw()); 59 | const config = api.config.toConfig(); 60 | 61 | // Common 62 | t.deepEqual( 63 | config.resolve.extensions.slice(0, newExtensions.length), 64 | newExtensions, 65 | ); 66 | 67 | const errors = validate(config); 68 | t.is(errors.length, 0); 69 | }); 70 | 71 | test('updates lint config by default', (t) => { 72 | const api = new Neutrino(); 73 | api.use(lint()); 74 | api.use(mw()); 75 | const options = api.config.module.rule('lint').use('eslint').get('options'); 76 | t.deepEqual(options.baseConfig.env, { 77 | browser: true, 78 | commonjs: true, 79 | es6: true, 80 | }); 81 | t.deepEqual(options.baseConfig.plugins, ['babel', 'react', 'react-hooks']); 82 | t.deepEqual(options.baseConfig.settings, { 83 | react: { 84 | version: 'detect', 85 | }, 86 | }); 87 | }); 88 | 89 | test('does not update lint config if useEslintrc true', (t) => { 90 | const api = new Neutrino(); 91 | api.use(lint({ eslint: { useEslintrc: true } })); 92 | api.use(mw()); 93 | const options = api.config.module.rule('lint').use('eslint').get('options'); 94 | t.deepEqual(options.baseConfig, {}); 95 | }); 96 | -------------------------------------------------------------------------------- /packages/standardjs/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | eslintrc.js 3 | -------------------------------------------------------------------------------- /packages/standardjs/eslintrc.js: -------------------------------------------------------------------------------- 1 | const neutrino = require('../neutrino'); 2 | const middleware = require('.'); 3 | 4 | module.exports = neutrino({ 5 | use: middleware(), 6 | options: { 7 | root: __dirname, 8 | }, 9 | }).eslintrc(); 10 | -------------------------------------------------------------------------------- /packages/standardjs/index.js: -------------------------------------------------------------------------------- 1 | const lint = require('@neutrinojs/eslint'); 2 | const { rules: standardRules } = require('eslint-config-standard'); 3 | 4 | module.exports = 5 | ({ eslint = {}, ...opts } = {}) => 6 | (neutrino) => { 7 | const baseConfig = eslint.baseConfig || {}; 8 | neutrino.use( 9 | lint({ 10 | ...opts, 11 | eslint: { 12 | ...eslint, 13 | baseConfig: { 14 | ...baseConfig, 15 | extends: [ 16 | require.resolve('eslint-config-standard'), 17 | require.resolve('eslint-config-standard-react'), 18 | ...(baseConfig.extends || []), 19 | ], 20 | rules: { 21 | // Disable rules for which there are eslint-plugin-babel replacements: 22 | // https://github.com/babel/eslint-plugin-babel#rules 23 | 'new-cap': 'off', 24 | 'no-invalid-this': 'off', 25 | 'object-curly-spacing': 'off', 26 | semi: 'off', 27 | 'no-unused-expressions': 'off', 28 | // Ensure the replacement rules use the options set by eslint-config-standard rather than ESLint defaults. 29 | 'babel/new-cap': standardRules['new-cap'], 30 | // eslint-config-standard doesn't currently have an explicit value for no-invalid-this, so 31 | // it defaults to off. The fallback is not added to the other rules, so changes in the 32 | // preset configuration layout doesn't silently cause rules to be disabled. 33 | 'babel/no-invalid-this': 34 | standardRules['no-invalid-this'] || 'off', 35 | 'babel/object-curly-spacing': 36 | standardRules['object-curly-spacing'], 37 | 'babel/semi': standardRules.semi, 38 | 'babel/no-unused-expressions': 39 | standardRules['no-unused-expressions'], 40 | ...baseConfig.rules, 41 | }, 42 | }, 43 | }, 44 | }), 45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /packages/standardjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/standardjs", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for linting projects using the StandardJS ESLint config", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "standardjs", 10 | "standard", 11 | "eslint" 12 | ], 13 | "author": "Eli Perelman ", 14 | "license": "MPL-2.0", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/standardjs" 19 | }, 20 | "homepage": "https://neutrinojs.org", 21 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "engines": { 26 | "node": ">=10", 27 | "npm": ">=5.4.0", 28 | "yarn": ">=1.2.1" 29 | }, 30 | "dependencies": { 31 | "@neutrinojs/eslint": "9.5.0", 32 | "eslint-config-standard": "^14.1.1", 33 | "eslint-config-standard-react": "^9.2.0", 34 | "eslint-plugin-import": "^2.22.1", 35 | "eslint-plugin-node": "^11.1.0", 36 | "eslint-plugin-promise": "^4.2.1", 37 | "eslint-plugin-react": "^7.21.5", 38 | "eslint-plugin-standard": "^4.1.0" 39 | }, 40 | "peerDependencies": { 41 | "eslint": "^6.0.0 || ^7.0.0", 42 | "neutrino": "^9.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/start-server/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/start-server/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Start Server Middleware 2 | 3 | `@neutrinojs/start-server` is Neutrino middleware for starting a Node.js server 4 | for a file upon completion of a build. 5 | 6 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 7 | 8 | ## Requirements 9 | 10 | - Node.js 10+ 11 | - Yarn v1.2.1+, or npm v5.4+ 12 | - Neutrino 9 13 | - webpack 4 14 | 15 | ## Installation 16 | 17 | `@neutrinojs/start-server` can be installed via the Yarn or npm clients. 18 | 19 | #### Yarn 20 | 21 | ```bash 22 | ❯ yarn add --dev @neutrinojs/start-server 23 | ``` 24 | 25 | #### npm 26 | 27 | ```bash 28 | ❯ npm install --save-dev @neutrinojs/start-server 29 | ``` 30 | 31 | ## Usage 32 | 33 | `@neutrinojs/start-server` can be consumed from the Neutrino API, middleware, or 34 | presets. Require this package and plug it into Neutrino: 35 | 36 | ```js 37 | const startServer = require('@neutrinojs/start-server'); 38 | 39 | // Use with default options, starting the server 40 | // for the main entry point, defaults to neutrino.options.mains.index 41 | neutrino.use(startServer()); 42 | 43 | // Usage with custom server file to start 44 | neutrino.use( 45 | startServer({ 46 | name: 'custom.js', 47 | // Override pluginId to add an additional start-server plugin instance 48 | pluginId: 'start-server', 49 | }), 50 | ); 51 | ``` 52 | 53 | ```js 54 | // Using in .neutrinorc.js 55 | const startServer = require('@neutrinojs/start-server'); 56 | 57 | // Use with default options, starting the server 58 | // for the main entry point, defaults to neutrino.options.mains.index 59 | module.exports = { 60 | use: [startServer()], 61 | }; 62 | 63 | // Usage with custom server file to start 64 | module.exports = { 65 | use: [ 66 | startServer({ 67 | name: 'custom.js', 68 | // Override pluginId to add an additional start-server plugin instance 69 | pluginId: 'start-server', 70 | }), 71 | ], 72 | }; 73 | ``` 74 | 75 | By default this middleware will start a server with the first main entry point 76 | configured in Neutrino, by default `src/index`. This middleware optionally 77 | accepts an object with a `name` property for a path to a module which to start 78 | the server. 79 | 80 | ## Customization 81 | 82 | `@neutrinojs/start-server` creates some conventions to make overriding the 83 | configuration easier once you are ready to make changes. 84 | 85 | ### Plugins 86 | 87 | The following is a list of plugins and their identifiers which can be 88 | overridden: 89 | 90 | | Name | Description | NODE_ENV | 91 | | -------------- | ---------------------------------------------------------------------------- | -------- | 92 | | `start-server` | Start a Node.js for the first configured main entry point or specified file. | all | 93 | 94 | ### Debugging 95 | 96 | You can start the Node.js server in `inspect` mode to debug the process by 97 | setting `neutrino.options.debug` to `true`. 98 | 99 | ## Contributing 100 | 101 | This middleware is part of the 102 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 103 | containing all resources for developing Neutrino and its core presets and 104 | middleware. Follow the 105 | [contributing guide](https://neutrinojs.org/contributing/) for details. 106 | 107 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/start-server.svg 108 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/start-server.svg 109 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/start-server 110 | -------------------------------------------------------------------------------- /packages/start-server/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | ({ pluginId = 'start-server', ...options } = {}) => 3 | (neutrino) => { 4 | neutrino.config 5 | .plugin(pluginId) 6 | .use(require.resolve('start-server-webpack-plugin'), [ 7 | { 8 | name: options.name, 9 | nodeArgs: neutrino.options.debug ? ['--inspect'] : [], 10 | }, 11 | ]); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/start-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/start-server", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for starting a server after a build", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "start", 10 | "server" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/start-server" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "start-server-webpack-plugin": "^2.2.5" 31 | }, 32 | "peerDependencies": { 33 | "neutrino": "^9.0.0", 34 | "webpack": "^4.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/start-server/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { name: 'app.js' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('uses middleware while debugging', (t) => { 20 | const api = new Neutrino({ debug: true }); 21 | 22 | t.notThrows(() => api.use(mw())); 23 | }); 24 | 25 | test('uses with options while debugging', (t) => { 26 | const api = new Neutrino({ debug: true }); 27 | 28 | t.notThrows(() => api.use(mw(options))); 29 | }); 30 | 31 | test('instantiates', (t) => { 32 | const api = new Neutrino(); 33 | 34 | api.use(mw()); 35 | 36 | t.notThrows(() => api.config.toConfig()); 37 | }); 38 | 39 | test('instantiates with options', (t) => { 40 | const api = new Neutrino(); 41 | 42 | api.use(mw(options)); 43 | 44 | t.notThrows(() => api.config.toConfig()); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/style-loader/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/style-loader/index.js: -------------------------------------------------------------------------------- 1 | const merge = require('deepmerge'); 2 | const { DuplicateRuleError } = require('neutrino/errors'); 3 | 4 | module.exports = 5 | (opts = {}) => 6 | (neutrino) => { 7 | const isProduction = process.env.NODE_ENV === 'production'; 8 | const modules = 'modules' in opts ? opts.modules : true; 9 | const modulesTest = 10 | opts.modulesTest || neutrino.regexFromExtensions(['module.css']); 11 | const options = merge( 12 | { 13 | test: neutrino.regexFromExtensions(['css']), 14 | ruleId: 'style', 15 | css: { 16 | importLoaders: opts.loaders ? opts.loaders.length : 0, 17 | }, 18 | style: {}, 19 | modules, 20 | modulesTest, 21 | loaders: [], 22 | extract: { 23 | enabled: isProduction, 24 | loader: { 25 | esModule: true, 26 | }, 27 | plugin: { 28 | filename: isProduction 29 | ? 'assets/[name].[contenthash:8].css' 30 | : 'assets/[name].css', 31 | }, 32 | }, 33 | }, 34 | opts, 35 | ); 36 | 37 | if (neutrino.config.module.rules.has(options.ruleId)) { 38 | throw new DuplicateRuleError('@neutrinojs/style-loader', options.ruleId); 39 | } 40 | 41 | const extractEnabled = options.extract && options.extract.enabled; 42 | const rules = [ 43 | merge(options, { 44 | oneOfId: 'normal', 45 | }), 46 | ]; 47 | 48 | if (options.modules) { 49 | rules.unshift( 50 | merge(options, { 51 | test: options.modulesTest, 52 | oneOfId: 'modules', 53 | css: { 54 | modules: options.modules, 55 | }, 56 | }), 57 | ); 58 | } 59 | 60 | rules.forEach((options) => { 61 | const styleRule = neutrino.config.module.rule(options.ruleId); 62 | const loaders = [ 63 | { 64 | loader: extractEnabled 65 | ? require.resolve('mini-css-extract-plugin/dist/loader') 66 | : require.resolve('style-loader'), 67 | options: extractEnabled ? options.extract.loader : options.style, 68 | useId: extractEnabled ? 'extract' : 'style', 69 | }, 70 | { 71 | loader: require.resolve('css-loader'), 72 | options: options.css, 73 | useId: 'css', 74 | }, 75 | ...options.loaders, 76 | ].map((loader, index) => ({ 77 | useId: `css-${index}`, 78 | ...(typeof loader === 'object' ? loader : { loader }), 79 | })); 80 | 81 | loaders.forEach((loader) => { 82 | styleRule 83 | .oneOf(options.oneOfId) 84 | .test(options.test) 85 | .use(loader.useId) 86 | .loader(loader.loader) 87 | .when(loader.options, (use) => use.options(loader.options)); 88 | }); 89 | }); 90 | 91 | if (extractEnabled) { 92 | neutrino.config 93 | .plugin('extract') 94 | .use(require.resolve('mini-css-extract-plugin'), [ 95 | options.extract.plugin, 96 | ]); 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /packages/style-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/style-loader", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for importing and loading stylesheets from modules", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "style", 10 | "css", 11 | "stylesheet" 12 | ], 13 | "author": "Eli Perelman ", 14 | "license": "MPL-2.0", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/neutrinojs/neutrino.git", 18 | "directory": "packages/style-loader" 19 | }, 20 | "homepage": "https://neutrinojs.org", 21 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "engines": { 26 | "node": ">=10", 27 | "npm": ">=5.4.0", 28 | "yarn": ">=1.2.1" 29 | }, 30 | "dependencies": { 31 | "css-loader": "^3.6.0", 32 | "deepmerge": "^1.5.2", 33 | "mini-css-extract-plugin": "^0.12.0", 34 | "style-loader": "^1.3.0" 35 | }, 36 | "peerDependencies": { 37 | "neutrino": "^9.0.0", 38 | "webpack": "^4.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/style-minify/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/style-minify/README.md: -------------------------------------------------------------------------------- 1 | # Neutrino Style Minify Middleware 2 | 3 | `@neutrinojs/style-minify` is Neutrino middleware for minifying styles using 4 | [`OptimizeCssAssetsPlugin`](https://www.npmjs.com/package/optimize-css-assets-webpack-plugin). 5 | This middleware is usually only added during production builds. 6 | 7 | [![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] 8 | 9 | ## Requirements 10 | 11 | - Node.js 10+ 12 | - Yarn v1.2.1+, or npm v5.4+ 13 | - Neutrino 9 14 | - webpack 4 15 | 16 | ## Installation 17 | 18 | `@neutrinojs/style-minify` can be installed via the Yarn or npm clients. 19 | 20 | #### Yarn 21 | 22 | ```bash 23 | ❯ yarn add --dev @neutrinojs/style-minify 24 | ``` 25 | 26 | #### npm 27 | 28 | ```bash 29 | ❯ npm install --save-dev @neutrinojs/style-minify 30 | ``` 31 | 32 | ## Usage 33 | 34 | `@neutrinojs/style-minify` can be consumed from the Neutrino API, middleware, or 35 | presets. Require this package and plug it into Neutrino: 36 | 37 | ```js 38 | const styleMinify = require('@neutrinojs/style-minify'); 39 | 40 | // Use with default options 41 | neutrino.use(styleMinify()); 42 | 43 | // Usage showing overriding options 44 | neutrino.use( 45 | styleMinify({ 46 | pluginId: 'optimize-css', 47 | plugin: { 48 | assetNameRegExp: /\.css$/g, 49 | cssProcessorOptions: {}, 50 | canPrint: true, 51 | }, 52 | }), 53 | ); 54 | ``` 55 | 56 | ```js 57 | // Using in .neutrinorc.js 58 | const styleMinify = require('@neutrinojs/style-minify'); 59 | 60 | // Use with default options 61 | module.exports = { 62 | use: [styleMinify()], 63 | }; 64 | 65 | // Usage showing overriding options 66 | module.exports = { 67 | use: [ 68 | styleMinify({ 69 | pluginId: 'optimize-css', 70 | plugin: { 71 | assetNameRegExp: /\.css$/g, 72 | cssProcessorOptions: {}, 73 | canPrint: true, 74 | }, 75 | }), 76 | ], 77 | }; 78 | ``` 79 | 80 | The `plugin` property is passed to 81 | [optimize-css-assets-webpack-plugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin#configuration). 82 | 83 | ## Customization 84 | 85 | `@neutrinojs/style-minify` creates some conventions to make overriding the 86 | configuration easier once you are ready to make changes. 87 | 88 | ### Plugins 89 | 90 | The following is a list of plugins and their identifiers which can be 91 | overridden: 92 | 93 | | Name | Description | NODE_ENV | 94 | | -------------- | --------------------------------------------- | -------- | 95 | | `optimize-css` | Minifies css using `OptimizeCssAssetsPlugin`. | all | 96 | 97 | ## Contributing 98 | 99 | This middleware is part of the 100 | [neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo 101 | containing all resources for developing Neutrino and its core presets and 102 | middleware. Follow the 103 | [contributing guide](https://neutrinojs.org/contributing/) for details. 104 | 105 | [npm-image]: https://img.shields.io/npm/v/@neutrinojs/style-minify.svg 106 | [npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/style-minify.svg 107 | [npm-url]: https://www.npmjs.com/package/@neutrinojs/style-minify 108 | -------------------------------------------------------------------------------- /packages/style-minify/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | ({ pluginId = 'optimize-css', plugin = {} } = {}) => 3 | (neutrino) => { 4 | neutrino.config 5 | .plugin(pluginId) 6 | .use(require.resolve('optimize-css-assets-webpack-plugin'), [plugin]); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/style-minify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/style-minify", 3 | "version": "9.5.0", 4 | "description": "Neutrino middleware for minifying styles", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-middleware", 9 | "minify", 10 | "style", 11 | "css", 12 | "cssnano" 13 | ], 14 | "author": "Tim Kelty ", 15 | "license": "MPL-2.0", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/neutrinojs/neutrino.git", 19 | "directory": "packages/style-minify" 20 | }, 21 | "homepage": "https://neutrinojs.org", 22 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 23 | "publishConfig": { 24 | "access": "public" 25 | }, 26 | "engines": { 27 | "node": ">=10", 28 | "npm": ">=5.4.0", 29 | "yarn": ">=1.2.1" 30 | }, 31 | "dependencies": { 32 | "optimize-css-assets-webpack-plugin": "^5.0.4" 33 | }, 34 | "peerDependencies": { 35 | "neutrino": "^9.0.0", 36 | "webpack": "^4.0.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/style-minify/test/middleware_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Neutrino from '../../neutrino/Neutrino'; 3 | 4 | const mw = (...args) => require('..')(...args); 5 | const options = { plugin: {}, pluginId: 'style-minify' }; 6 | 7 | test('loads middleware', (t) => { 8 | t.notThrows(() => require('..')); 9 | }); 10 | 11 | test('uses middleware', (t) => { 12 | t.notThrows(() => new Neutrino().use(mw())); 13 | }); 14 | 15 | test('uses with options', (t) => { 16 | t.notThrows(() => new Neutrino().use(mw(options))); 17 | }); 18 | 19 | test('instantiates', (t) => { 20 | const api = new Neutrino(); 21 | 22 | api.use(mw()); 23 | 24 | t.notThrows(() => api.config.toConfig()); 25 | }); 26 | 27 | test('instantiates with options', (t) => { 28 | const api = new Neutrino(); 29 | 30 | api.use(mw(options)); 31 | 32 | t.notThrows(() => api.config.toConfig()); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/vue/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/vue", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset adding Vue.js support.", 5 | "main": "src/index.js", 6 | "author": "Capi Etheriel (https://barraponto.blog.br)", 7 | "license": "MPL-2.0", 8 | "keywords": [ 9 | "neutrino", 10 | "neutrino-preset", 11 | "vue", 12 | "web", 13 | "hot module replacement" 14 | ], 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "engines": { 19 | "node": ">=10", 20 | "npm": ">=5.4.0", 21 | "yarn": ">=1.2.1" 22 | }, 23 | "dependencies": { 24 | "@neutrinojs/web": "9.5.0", 25 | "css-loader": "^3.6.0", 26 | "deepmerge": "^1.5.2", 27 | "eslint-plugin-react": "^7.21.5", 28 | "eslint-plugin-vue": "^6.2.2", 29 | "vue-loader": "^15.9.6", 30 | "vue-style-loader": "^4.1.2", 31 | "vue-template-compiler": "^2.6.12" 32 | }, 33 | "devDependencies": { 34 | "vue": "^2.6.12" 35 | }, 36 | "peerDependencies": { 37 | "neutrino": "^9.0.0", 38 | "webpack": "^4.0.0", 39 | "webpack-cli": "^3.0.0", 40 | "webpack-dev-server": "^3.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/vue/test/vue_test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { validate } from 'webpack'; 3 | import lint from '../../eslint'; 4 | import Neutrino from '../../neutrino/Neutrino'; 5 | 6 | const mw = (...args) => require('..')(...args); 7 | const originalNodeEnv = process.env.NODE_ENV; 8 | const expectedExtensions = ['.wasm', '.mjs', '.jsx', '.vue', '.js', '.json']; 9 | 10 | test.afterEach(() => { 11 | // Restore the original NODE_ENV after each test (which Ava defaults to 'test'). 12 | process.env.NODE_ENV = originalNodeEnv; 13 | }); 14 | 15 | test('loads preset', (t) => { 16 | t.notThrows(() => require('..')); 17 | }); 18 | 19 | test('uses preset', (t) => { 20 | t.notThrows(() => new Neutrino().use(mw())); 21 | }); 22 | 23 | test('valid preset production', (t) => { 24 | process.env.NODE_ENV = 'production'; 25 | const api = new Neutrino(); 26 | api.use(mw()); 27 | const config = api.config.toConfig(); 28 | 29 | const errors = validate(config); 30 | t.deepEqual(config.resolve.extensions, expectedExtensions); 31 | 32 | t.is(errors.length, 0); 33 | }); 34 | 35 | test('valid preset development', (t) => { 36 | process.env.NODE_ENV = 'development'; 37 | const api = new Neutrino(); 38 | api.use(mw()); 39 | const config = api.config.toConfig(); 40 | 41 | const errors = validate(config); 42 | t.deepEqual(config.resolve.extensions, expectedExtensions); 43 | 44 | t.is(errors.length, 0); 45 | }); 46 | 47 | test('updates lint config by default', (t) => { 48 | const api = new Neutrino(); 49 | api.use(lint()); 50 | api.use(mw()); 51 | 52 | const lintRule = api.config.module.rule('lint'); 53 | t.deepEqual(lintRule.get('test'), /\.(mjs|jsx|vue|js)$/); 54 | t.deepEqual(lintRule.use('eslint').get('options').baseConfig, { 55 | env: { 56 | browser: true, 57 | commonjs: true, 58 | es6: true, 59 | }, 60 | extends: ['plugin:vue/base'], 61 | globals: { 62 | process: true, 63 | }, 64 | parser: 'vue-eslint-parser', 65 | parserOptions: { 66 | ecmaVersion: 2018, 67 | parser: 'babel-eslint', 68 | sourceType: 'module', 69 | }, 70 | plugins: ['babel', 'vue'], 71 | root: true, 72 | }); 73 | }); 74 | 75 | test('does not update lint config if useEslintrc true', (t) => { 76 | const api = new Neutrino(); 77 | api.use(lint({ eslint: { useEslintrc: true } })); 78 | api.use(mw()); 79 | const options = api.config.module.rule('lint').use('eslint').get('options'); 80 | t.deepEqual(options.baseConfig, {}); 81 | }); 82 | 83 | test('adds style oneOfs in order', (t) => { 84 | const api = new Neutrino(); 85 | api.use(mw()); 86 | const { oneOfs } = api.config.module.rule('style'); 87 | t.deepEqual( 88 | oneOfs.values().map((oneOf) => oneOf.name), 89 | ['vue-modules', 'vue-normal', 'modules', 'normal'], 90 | ); 91 | }); 92 | 93 | test('replaces style-loader with vue-style-loader in development', (t) => { 94 | process.env.NODE_ENV = 'development'; 95 | const api = new Neutrino(); 96 | api.use(mw()); 97 | 98 | api.config.module 99 | .rule('style') 100 | .oneOfs.values() 101 | .filter((oneOf) => oneOf.name.startsWith('vue-')) 102 | .forEach((oneOf) => { 103 | t.is( 104 | oneOf.use('style').get('loader'), 105 | require.resolve('vue-style-loader'), 106 | ); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /packages/web/.npmignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /packages/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@neutrinojs/web", 3 | "version": "9.5.0", 4 | "description": "Neutrino preset for building generic web applications", 5 | "main": "index.js", 6 | "keywords": [ 7 | "neutrino", 8 | "neutrino-preset", 9 | "web", 10 | "hot module reload" 11 | ], 12 | "author": "Eli Perelman ", 13 | "license": "MPL-2.0", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/neutrinojs/neutrino.git", 17 | "directory": "packages/web" 18 | }, 19 | "homepage": "https://neutrinojs.org", 20 | "bugs": "https://github.com/neutrinojs/neutrino/issues", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "engines": { 25 | "node": ">=10", 26 | "npm": ">=5.4.0", 27 | "yarn": ">=1.2.1" 28 | }, 29 | "dependencies": { 30 | "@babel/core": "^7.12.10", 31 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 32 | "@babel/preset-env": "^7.12.11", 33 | "@neutrinojs/clean": "9.5.0", 34 | "@neutrinojs/compile-loader": "9.5.0", 35 | "@neutrinojs/dev-server": "9.5.0", 36 | "@neutrinojs/font-loader": "9.5.0", 37 | "@neutrinojs/html-loader": "9.5.0", 38 | "@neutrinojs/html-template": "9.5.0", 39 | "@neutrinojs/image-loader": "9.5.0", 40 | "@neutrinojs/style-loader": "9.5.0", 41 | "babel-merge": "^3.0.0", 42 | "deepmerge": "^1.5.2" 43 | }, 44 | "peerDependencies": { 45 | "neutrino": "^9.0.0", 46 | "webpack": "^4.0.0", 47 | "webpack-cli": "^3.0.0", 48 | "webpack-dev-server": "^3.0.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":maintainLockFilesWeekly", 5 | ":prNotPending", 6 | ":semanticCommitsDisabled" 7 | ], 8 | "reviewers": ["team:neutrinojs/core-contributors"], 9 | "pinVersions": false 10 | } 11 | -------------------------------------------------------------------------------- /scripts/build-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # Switch to the root of the repository. 6 | cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" 7 | 8 | mkdocs build 9 | 10 | # Some of the docs are generated from the individual package READMEs, 11 | # which have to use absolute URLs so that they work on the NPM package 12 | # pages. This converts them to site-root relative URLs, so that links 13 | # between packages target the current branch's version of the docs. 14 | # https://neutrinojs.org/ -> Not changed (since used for the "current version" link) 15 | # https://neutrinojs.org/foo/ -> /foo/ 16 | find build/ -type f -name '*.html' -exec sed -ri 's|https://neutrinojs\.org/(\w+)|/\1|g' {} + 17 | -------------------------------------------------------------------------------- /scripts/test-create-project-ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ "$CREATE_PROJECT_YARN" = "true" ]] 6 | then 7 | export YARN_AUTH_TOKEN="//localhost:4873/:_authToken=token" 8 | 9 | # Start verdaccio registry proxy in the background 10 | yarn verdaccio --config verdaccio.yarn.yml & 11 | 12 | # Verdaccio isn't ready to immediately accept connections, so we need to wait 13 | while ! nc -zw 1 localhost 4873; do sleep 1; done 14 | 15 | # Publish all monorepo packages to the verdaccio registry. 16 | # The version will be bumped to the next minor version with a pre-release suffix, 17 | # and the package.json changes left in the working directory so that create-project 18 | # can read the correct version for installing matching monorepo packages. 19 | yarn release:ci 20 | 21 | # Run the integration tests, which will install packages 22 | # from the verdaccio registry 23 | yarn test:create-project 24 | 25 | # Remove cached Neutrino packages to avoid Travis cache churn. 26 | # Not using `yarn cache clean` since it doesn't support globs, 27 | # and does nothing more than call `fs.unlink(dir)` anyway. 28 | YARN_CACHE_DIR="$(yarn cache dir)" 29 | rm -rf "${YARN_CACHE_DIR}"/*-neutrino-*/ "${YARN_CACHE_DIR}"/*-@neutrinojs/ 30 | else 31 | echo "//localhost:4873/:_authToken=token" > .npmrc 32 | 33 | # Start verdaccio registry proxy in the background 34 | node_modules/.bin/verdaccio --config verdaccio.npm.yml & 35 | 36 | # Verdaccio isn't ready to immediately accept connections, so we need to wait 37 | while ! nc -zw 1 localhost 4873; do sleep 1; done 38 | 39 | # legacy peer deps is needed 40 | npm config set legacy-peer-deps true 41 | 42 | # Publish all monorepo packages to the verdaccio registry. 43 | # The version will be bumped to the next minor version with a pre-release suffix, 44 | # and the package.json changes left in the working directory so that create-project 45 | # can read the correct version for installing matching monorepo packages. 46 | npm run release:ci 47 | 48 | # Run the integration tests, which will install packages 49 | # from the verdaccio registry 50 | npm run test:create-project 51 | 52 | # Remove cached Neutrino packages to avoid Travis cache churn. 53 | npm_config_cache="$(npm config get cache --global)" 54 | rm -rf "${npm_config_cache}"/*-neutrino-*/ "${npm_config_cache}"/*-@neutrinojs/ 55 | fi 56 | 57 | -------------------------------------------------------------------------------- /verdaccio.npm.yml: -------------------------------------------------------------------------------- 1 | store: 2 | # Use ephemeral verdaccio-memory storage instead of the default of filesystem. 3 | memory: 4 | # Increase maximum number of packages that can be stored (default 1000). 5 | limit: 10000 6 | uplinks: 7 | npmjs: 8 | url: https://registry.npmjs.org/ 9 | # Increase number of failed requests before disabling uplink (default 2). 10 | max_fails: 20 11 | # Increase the time before cached package metadata is re-fetched (default 2m). 12 | maxage: 10m 13 | # Disable caching of package tarballs since it duplicates the local yarn cache. 14 | cache: false 15 | # Increase the max time when a request becomes a failure (default 5m). 16 | fail_timeout: 10m 17 | packages: 18 | 'neutrino': 19 | access: $anonymous 20 | publish: $anonymous 21 | '@neutrinojs/*': 22 | access: $anonymous 23 | publish: $anonymous 24 | '**': 25 | access: $anonymous 26 | proxy: npmjs 27 | logs: 28 | - { type: stdout, format: pretty, level: warn } 29 | server: 30 | # Set to 0 to avoid EINTEGRITY issues when installing from npm. 31 | keepAliveTimeout: 0 32 | -------------------------------------------------------------------------------- /verdaccio.yarn.yml: -------------------------------------------------------------------------------- 1 | store: 2 | # Use ephemeral verdaccio-memory storage instead of the default of filesystem. 3 | memory: 4 | # Increase maximum number of packages that can be stored (default 1000). 5 | limit: 10000 6 | uplinks: 7 | yarnpkg: 8 | url: https://registry.yarnpkg.com/ 9 | # Increase number of failed requests before disabling uplink (default 2). 10 | max_fails: 5 11 | # Increase the time before cached package metadata is re-fetched (default 2m). 12 | maxage: 10m 13 | # Disable caching of package tarballs since it duplicates the local yarn cache. 14 | cache: false 15 | packages: 16 | 'neutrino': 17 | access: $anonymous 18 | publish: $anonymous 19 | '@neutrinojs/*': 20 | access: $anonymous 21 | publish: $anonymous 22 | '**': 23 | access: $anonymous 24 | proxy: yarnpkg 25 | logs: 26 | - { type: stdout, format: pretty, level: warn } 27 | --------------------------------------------------------------------------------