├── .editorconfig ├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── BACKERS.md ├── LICENSE ├── README.md ├── circle.yml ├── core ├── dev-utils │ ├── CHANGELOG.md │ ├── InlineChunkHtmlPlugin.js │ ├── WatchMissingNodeModulesPlugin.js │ ├── clearConsole.js │ ├── colors.js │ ├── formatWebpackMessages.js │ ├── hotDevClient.js │ ├── launchEditorEndpoint.js │ ├── open.js │ ├── openBrowser.js │ ├── openChrome.applescript │ ├── package.json │ ├── prepareProxy.js │ ├── prettyBytes.js │ ├── printServeMessage.js │ ├── refreshOverlayInterop.js │ ├── runCompiler.js │ └── skipServiceWorker.js ├── logger │ ├── index.js │ └── package.json ├── poi │ ├── CHANGELOG.md │ ├── README.md │ ├── __test__ │ │ ├── __snapshots__ │ │ │ └── format.test.js.snap │ │ └── format.test.js │ ├── babel.js │ ├── bin │ │ └── cli.js │ ├── lib │ │ ├── Hooks.js │ │ ├── WebpackUtils.js │ │ ├── babel │ │ │ └── preset.js │ │ ├── index.js │ │ ├── plugins │ │ │ ├── command-options.js │ │ │ ├── config-babel.js │ │ │ ├── config-css.js │ │ │ ├── config-electron.js │ │ │ ├── config-eval.js │ │ │ ├── config-font.js │ │ │ ├── config-html.js │ │ │ ├── config-image.js │ │ │ ├── config-jsx-import.js │ │ │ ├── config-misc-loaders.js │ │ │ ├── config-react-refresh.js │ │ │ ├── config-reason.js │ │ │ ├── config-vue.js │ │ │ ├── config-yarn-pnp.js │ │ │ ├── eject-html.js │ │ │ ├── serve.js │ │ │ └── watch.js │ │ ├── utils │ │ │ ├── PoiError.js │ │ │ ├── WebpackChain.js │ │ │ ├── __test__ │ │ │ │ └── plugins.test.js │ │ │ ├── createConfigLoader.js │ │ │ ├── getFileNames.js │ │ │ ├── isLocalPath.js │ │ │ ├── loadEnvs.js │ │ │ ├── mergeConfig.js │ │ │ ├── parseArgs.js │ │ │ ├── plugins.js │ │ │ ├── spinner.js │ │ │ └── validateConfig.js │ │ └── webpack │ │ │ ├── PrintStatusPlugin.js │ │ │ ├── babel-loader.js │ │ │ ├── default-template.html │ │ │ ├── eval-loader.js │ │ │ ├── reason-loader.js │ │ │ └── webpack.config.js │ ├── package.json │ └── webpack.config.js └── test-utils │ ├── CHANGELOG.md │ ├── createProject.js │ └── package.json ├── create-poi-app ├── CHANGELOG.md ├── README.md ├── bin │ └── cli.js ├── generator │ ├── __test__ │ │ └── index.test.js │ ├── saofile.js │ └── templates │ │ ├── js │ │ └── src │ │ │ ├── index.js │ │ │ └── index.test.js │ │ ├── linter-tslint │ │ └── tslint.json │ │ ├── linter-xo │ │ └── .eslintrc.js │ │ ├── main │ │ ├── README.md │ │ ├── _gitignore │ │ ├── package.json │ │ ├── poi.config.js │ │ ├── public │ │ │ └── favicon.ico │ │ └── src │ │ │ └── assets │ │ │ └── css │ │ │ └── style.css │ │ ├── pwa │ │ ├── public │ │ │ ├── img │ │ │ │ └── icons │ │ │ │ │ ├── apple-touch-icon-152x152.png │ │ │ │ │ ├── msapplication-icon-144x144.png │ │ │ │ │ └── safari-mask-icon.svg │ │ │ └── manifest.json │ │ └── src │ │ │ └── registerServiceWorker.js │ │ └── ts │ │ ├── src │ │ ├── index.test.ts │ │ └── index.ts │ │ └── tsconfig.json └── package.json ├── lerna.json ├── other-packages ├── babel-plugin-assets-named-imports │ ├── CHANGELOG.md │ ├── __test__ │ │ └── index.test.js │ ├── index.js │ └── package.json ├── pnp-webpack-plugin │ ├── CHANGELOG.md │ ├── index.js │ └── package.json └── pwa-html-webpack-plugin │ ├── index.js │ └── package.json ├── package.json ├── plugins ├── astroturf │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── index.test.js │ └── package.json ├── bundle-report │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ └── package.json ├── eslint │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ └── package.json ├── html-entry │ ├── CHANGELOG.md │ ├── README.md │ ├── example │ │ ├── foo.svg │ │ ├── index.html │ │ ├── main.js │ │ ├── meow.png │ │ └── style.css │ ├── lib │ │ ├── html-entry-loader.js │ │ ├── index.js │ │ ├── template-settings.js │ │ └── utils.js │ └── package.json ├── karma │ ├── CHANGELOG.md │ ├── README.md │ ├── example │ │ └── index.test.js │ ├── lib │ │ ├── index.js │ │ └── run-karma.js │ └── package.json ├── puppet │ ├── CHANGELOG.md │ ├── README.md │ ├── example │ │ ├── mocha.test.js │ │ └── tape.test.js │ ├── lib │ │ ├── index.js │ │ ├── mocha │ │ │ ├── after.js │ │ │ └── before.js │ │ ├── run.js │ │ ├── shared │ │ │ └── before.js │ │ ├── tape │ │ │ └── before.js │ │ └── utils.js │ └── package.json ├── pwa │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ └── package.json ├── typescript │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ └── package.json └── vue-static │ ├── CHANGELOG.md │ ├── README.md │ ├── example │ ├── about.vue │ ├── home.vue │ ├── index.js │ └── style.css │ ├── lib │ ├── app │ │ ├── create-app.js │ │ ├── entry-client.js │ │ └── entry-server.js │ ├── generate.js │ └── index.js │ └── package.json ├── tasks └── test.sh ├── test └── kitchensink │ ├── .poirc │ ├── package.json │ ├── src │ └── features │ │ └── webpack │ │ ├── AssetsNamedImports.test.js │ │ ├── CssInclusion.js │ │ ├── CssInclusion.test.js │ │ ├── CssModulesInclusion.js │ │ ├── CssModulesInclusion.test.js │ │ ├── EvalLoader.test.js │ │ ├── ImageInclusion.js │ │ ├── ImageInclusion.test.js │ │ ├── JsonInclusion.js │ │ ├── JsonInclusion.test.js │ │ ├── SassInclusion.js │ │ ├── SassInclusion.test.js │ │ ├── SassModulesInclusion.js │ │ ├── SassModulesInclusion.test.js │ │ ├── ScssInclusion.js │ │ ├── ScssInclusion.test.js │ │ ├── ScssModulesInclusion.js │ │ ├── ScssModulesInclusion.test.js │ │ ├── SvgInCss.js │ │ ├── SvgInCss.test.js │ │ ├── SvgInclusion.js │ │ ├── SvgInclusion.test.js │ │ └── assets │ │ ├── abstract.json │ │ ├── data.eval.js │ │ ├── example.md │ │ ├── index.module.css │ │ ├── index.module.sass │ │ ├── index.module.scss │ │ ├── logo.svg │ │ ├── sass-styles.module.sass │ │ ├── sass-styles.sass │ │ ├── scss-styles.module.scss │ │ ├── scss-styles.scss │ │ ├── style.css │ │ ├── style.module.css │ │ ├── svg.css │ │ ├── text.md │ │ └── tiniest-cat.jpg │ └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: egoist # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | open_collective: # Replace with a single Open Collective username 5 | ko_fi: support_egoist 6 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 7 | custom: # Replace with a single custom sponsorship URL 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | dist 4 | /.changelog 5 | .vscode 6 | .idea 7 | .DS_Store 8 | .test-projects 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "bracketSpacing": true 5 | } 6 | -------------------------------------------------------------------------------- /BACKERS.md: -------------------------------------------------------------------------------- 1 | # Sponsors & Backers 2 | 3 | Poi is an MIT-licensed open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by awesome backers and sponsors. If you'd like to join them, please consider: 4 | 5 | - [Become a backer or sponsor on Patreon](https://patreon.com/egoist) 6 | - [Donate via PayPal](https://paypal.me/egoistian) 7 | - [Donate via AliPay](https://user-images.githubusercontent.com/8784712/38684215-c7b78590-3ea1-11e8-9812-91569ee72eaa.png) 8 | - [Donate via Wechat](https://user-images.githubusercontent.com/8784712/38684192-bceaad18-3ea1-11e8-9a38-a4e0eb79b7a7.png) 9 | 10 | ## Backers 11 | 12 | - Shinya Katayama [@ktsn](https://github.com/ktsn) 13 | - HANATANI Takuma [@potato4d](https://github.com/potato4d) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) EGOIST <0x142857@gmail.com> (https://egoist.sh) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Poi has been deprecated, please migrate to [Vite](https://vitejs.dev), contact me personally if you need help. 2 | 3 |

4 | 5 |

6 |
7 | 8 | [![npm version](https://badgen.net/npm/v/poi)](https://npm.im/poi) [![build status](https://badgen.net/circleci/github/egoist/poi/master)](https://circleci.com/gh/egoist/poi/tree/master) [![npm downloads](https://badgen.net/npm/dm/poi)](https://npm.im/poi) [![poi twitter](https://badgen.net/badge//@poi__js/1da1f2?icon=twitter)](https://twitter.com/poi__js) 9 | 10 | Poi is a bundler built on the top of webpack, trying to make developing and bundling apps with webpack as easy as possible. 11 | 12 | **The Poi project is supported by our [Backers](./BACKERS.md) and funded through [Patreon](https://patreon.com/egoist).** 13 | 14 | ## Features 15 | 16 | - 📦 Out of box support for JS, CSS, File assets and more. 17 | - ⚛ Framework-agnostic but also support JSX, Vue and more with no configs. 18 | - 🔌 Great extensibility. 19 | - 🐙 Fits most web apps, npm libs. 20 | - 🚨 Great development experience. 21 | 22 | ## Quick Overview 23 | 24 | Before we get started, ensure that you have installed Node.js (>=8) and Yarn (or npm) on your machine. 25 | 26 | ### Get Started Immediately 27 | 28 | ```bash 29 | yarn global add create-poi-app 30 | create-poi-app my-app 31 | 32 | cd my-app 33 | npm run dev 34 | ``` 35 | 36 | Then open http://localhost:4000 to see your app.
37 | When you’re ready to deploy to production, create a minified bundle with `npm run build`. 38 | 39 | ### Get Started Manually 40 | 41 | Inside an empty project, run `yarn init` or `npm init` to create a `package.json` and install Poi: 42 | 43 | ```bash 44 | yarn init 45 | yarn add poi --dev 46 | ``` 47 | 48 | Now all you need is to create an entry file, like if you're building a website, just create an `index.js`: 49 | 50 | ```js 51 | const el = document.createElement('div') 52 | el.textContent = 'Hello Poi!' 53 | 54 | document.body.appendChild(el) 55 | ``` 56 | 57 | Now if you run: 58 | 59 | ```bash 60 | yarn poi --serve 61 | ``` 62 | 63 | You will get a URL like `http://localhost:4000` which you can open to preview the app. 64 | 65 | Next let's start adding some dependencies like a CSS file `style.module.css`: 66 | 67 | ```css 68 | .title { 69 | color: pink; 70 | } 71 | ``` 72 | 73 | ```js 74 | import styles from './style.module.css' 75 | 76 | const el = document.createElement('div') 77 | el.className = styles.title 78 | el.textContent = 'Hello Poi!' 79 | 80 | document.body.appendChild(el) 81 | ``` 82 | 83 | Save it and the browser will automatically reload to apply the changes! 84 | 85 | ## Documentation 86 | 87 | 📚 https://poi.js.org 88 | 89 | You can improve it by sending pull requests to [this repository](https://github.com/poi-bundler/website). 90 | 91 | Check out [this repository](https://github.com/poi-bundler/examples) for more examples. 92 | 93 | ## Community 94 | 95 | All feedback and suggestions are welcome! 96 | 97 | - 💬 Join the community on [Spectrum](https://spectrum.chat/poi). 98 | - 📣 Stay up to date on new features and announcements on [Twitter @poi\_\_js](https://twitter.com/poi__js). 99 | 100 | ## Credits 101 | 102 | Poi v12 wouldn't exist without the inspirations from following projects: 103 | 104 | - Webpack 105 | - Parcel 2 106 | - Poi itself 107 | - Vue CLI 3 108 | - Create React App 109 | 110 | ## License 111 | 112 | MIT © [EGOIST](https://egoist.sh) 113 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/repo 5 | docker: 6 | - image: circleci/node:10-browsers 7 | branches: 8 | ignore: 9 | - gh-pages # list of branches to ignore 10 | - /release\/.*/ # or ignore regexes 11 | steps: 12 | - checkout 13 | - restore_cache: 14 | key: dependency-cache-{{ checksum "yarn.lock" }} 15 | - run: 16 | name: install dependences 17 | command: yarn 18 | - save_cache: 19 | key: dependency-cache-{{ checksum "yarn.lock" }} 20 | paths: 21 | - ./node_modules 22 | - run: 23 | name: test 24 | command: yarn test 25 | -------------------------------------------------------------------------------- /core/dev-utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [12.1.6](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.5...@poi/dev-utils@12.1.6) (2020-08-19) 7 | 8 | ### Bug Fixes 9 | 10 | - make react-refresh work better with error overlay ([e6deed4](https://github.com/egoist/poi/commit/e6deed4)) 11 | 12 | ## [12.1.5](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.4...@poi/dev-utils@12.1.5) (2020-07-13) 13 | 14 | **Note:** Version bump only for package @poi/dev-utils 15 | 16 | ## [12.1.4](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.3...@poi/dev-utils@12.1.4) (2020-04-30) 17 | 18 | **Note:** Version bump only for package @poi/dev-utils 19 | 20 | ## [12.1.3](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.2...@poi/dev-utils@12.1.3) (2019-08-09) 21 | 22 | ### Bug Fixes 23 | 24 | - keep the trailing slash of `output.publicUrl` ([#612](https://github.com/egoist/poi/issues/612)) ([56bd612](https://github.com/egoist/poi/commit/56bd612)) 25 | 26 | ## [12.1.2](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.1...@poi/dev-utils@12.1.2) (2019-07-27) 27 | 28 | ### Bug Fixes 29 | 30 | - Append `poi -s` output URLs with `output.publicUrl` ([#587](https://github.com/egoist/poi/issues/587)) ([fcd70f7](https://github.com/egoist/poi/commit/fcd70f7)) 31 | 32 | ### Features 33 | 34 | - enable https one the preview URLs ([#611](https://github.com/egoist/poi/issues/611)) ([cda0ec2](https://github.com/egoist/poi/commit/cda0ec2)) 35 | 36 | ## [12.1.1](https://github.com/egoist/poi/compare/@poi/dev-utils@12.1.0...@poi/dev-utils@12.1.1) (2019-01-23) 37 | 38 | ### Bug Fixes 39 | 40 | - format build time in human-readable format ([a89ecd0](https://github.com/egoist/poi/commit/a89ecd0)) 41 | - use a new port if the port is already used ([62053e5](https://github.com/egoist/poi/commit/62053e5)) 42 | 43 | # [12.1.0](https://github.com/egoist/poi/compare/@poi/dev-utils@12.0.3...@poi/dev-utils@12.1.0) (2019-01-09) 44 | 45 | ### Bug Fixes 46 | 47 | - **dev-utils:** refactor hotDevClient to ES5 compat ([#522](https://github.com/egoist/poi/issues/522)) ([480bce5](https://github.com/egoist/poi/commit/480bce5)), closes [#515](https://github.com/egoist/poi/issues/515) 48 | 49 | ### Features 50 | 51 | - show memory usage ([75f1376](https://github.com/egoist/poi/commit/75f1376)) 52 | 53 | ## [12.0.3](https://github.com/egoist/poi/compare/@poi/dev-utils@12.0.2...@poi/dev-utils@12.0.3) (2018-12-21) 54 | 55 | ### Bug Fixes 56 | 57 | - **cli:** only open browser on the first successful build ([13b1ac8](https://github.com/egoist/poi/commit/13b1ac8)) 58 | -------------------------------------------------------------------------------- /core/dev-utils/InlineChunkHtmlPlugin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict'; 3 | 4 | class InlineChunkHtmlPlugin { 5 | constructor(htmlWebpackPlugin, tests) { 6 | this.htmlWebpackPlugin = htmlWebpackPlugin; 7 | this.tests = tests; 8 | } 9 | 10 | getInlinedTag(publicPath, assets, tag) { 11 | if (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) { 12 | return tag; 13 | } 14 | const scriptName = tag.attributes.src.replace(publicPath, ''); 15 | if (!this.tests.some(test => scriptName.match(test))) { 16 | return tag; 17 | } 18 | const asset = assets[scriptName]; 19 | if (asset == null) { 20 | return tag; 21 | } 22 | return { tagName: 'script', innerHTML: asset.source(), closeTag: true }; 23 | } 24 | 25 | apply(compiler) { 26 | let publicPath = compiler.options.output.publicPath; 27 | if (!publicPath.endsWith('/')) { 28 | publicPath += '/'; 29 | } 30 | 31 | compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => { 32 | const tagFunction = tag => 33 | this.getInlinedTag(publicPath, compilation.assets, tag); 34 | 35 | const hooks = this.htmlWebpackPlugin.getHooks(compilation); 36 | hooks.alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => { 37 | assets.headTags = assets.headTags.map(tagFunction); 38 | assets.bodyTags = assets.bodyTags.map(tagFunction); 39 | }); 40 | 41 | // Still emit the runtime chunk for users who do not use our generated 42 | // index.html file. 43 | // hooks.afterEmit.tap('InlineChunkHtmlPlugin', () => { 44 | // Object.keys(compilation.assets).forEach(assetName => { 45 | // if (this.tests.some(test => assetName.match(test))) { 46 | // delete compilation.assets[assetName]; 47 | // } 48 | // }); 49 | // }); 50 | }); 51 | } 52 | } 53 | 54 | module.exports = InlineChunkHtmlPlugin; 55 | -------------------------------------------------------------------------------- /core/dev-utils/WatchMissingNodeModulesPlugin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // This Webpack plugin ensures `npm install ` forces a project rebuild. 3 | // We’re not sure why this isn't Webpack's default behavior. 4 | // See https://github.com/facebook/create-react-app/issues/186. 5 | 6 | 'use strict' 7 | 8 | class WatchMissingNodeModulesPlugin { 9 | constructor(nodeModulesPath) { 10 | this.nodeModulesPath = nodeModulesPath 11 | } 12 | 13 | apply(compiler) { 14 | compiler.hooks.emit.tap('WatchMissingNodeModulesPlugin', compilation => { 15 | const missingDeps = [...compilation.missingDependencies] 16 | const nodeModulesPath = this.nodeModulesPath 17 | 18 | // If any missing files are expected to appear in node_modules... 19 | if (missingDeps.some(file => file.includes(nodeModulesPath))) { 20 | // ...tell webpack to watch node_modules recursively until they appear. 21 | compilation.contextDependencies.add(nodeModulesPath) 22 | } 23 | }) 24 | } 25 | } 26 | 27 | module.exports = WatchMissingNodeModulesPlugin 28 | -------------------------------------------------------------------------------- /core/dev-utils/clearConsole.js: -------------------------------------------------------------------------------- 1 | function clearConsole() { 2 | process.stdout.write('\u001Bc') 3 | } 4 | 5 | module.exports = clearConsole 6 | -------------------------------------------------------------------------------- /core/dev-utils/colors.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /** 3 | * This file should be written in ES5 4 | * Code is taken from https://github.com/jorgebucaran/colorette/blob/master/index.js 5 | * Copy it to https://buble.surge.sh and paste here 6 | */ 7 | "use strict" 8 | 9 | var enabled = 10 | process.env.FORCE_COLOR || 11 | process.platform === "win32" || 12 | (process.stdout && process.stdout.isTTY && process.env.TERM && process.env.TERM !== "dumb") 13 | 14 | var rawInit = function (open, close, searchRegex, replaceValue) { return function (s) { return enabled 15 | ? open + 16 | (~(s += "").indexOf(close, 4) // skip opening \x1b[ 17 | ? s.replace(searchRegex, replaceValue) 18 | : s) + 19 | close 20 | : s; }; } 21 | 22 | var init = function (open, close) { 23 | return rawInit( 24 | ("\u001b[" + open + "m"), 25 | ("\u001b[" + close + "m"), 26 | new RegExp(("\\x1b\\[" + close + "m"), "g"), 27 | ("\u001b[" + open + "m") 28 | ) 29 | } 30 | 31 | module.exports = { 32 | options: Object.defineProperty({}, "enabled", { 33 | get: function () { return enabled; }, 34 | set: function (value) { return (enabled = value); } 35 | }), 36 | reset: init(0, 0), 37 | bold: rawInit("\x1b[1m", "\x1b[22m", /\x1b\[22m/g, "\x1b[22m\x1b[1m"), 38 | dim: rawInit("\x1b[2m", "\x1b[22m", /\x1b\[22m/g, "\x1b[22m\x1b[2m"), 39 | italic: init(3, 23), 40 | underline: init(4, 24), 41 | inverse: init(7, 27), 42 | hidden: init(8, 28), 43 | strikethrough: init(9, 29), 44 | black: init(30, 39), 45 | red: init(31, 39), 46 | green: init(32, 39), 47 | yellow: init(33, 39), 48 | blue: init(34, 39), 49 | magenta: init(35, 39), 50 | cyan: init(36, 39), 51 | white: init(37, 39), 52 | gray: init(90, 39), 53 | bgBlack: init(40, 49), 54 | bgRed: init(41, 49), 55 | bgGreen: init(42, 49), 56 | bgYellow: init(43, 49), 57 | bgBlue: init(44, 49), 58 | bgMagenta: init(45, 49), 59 | bgCyan: init(46, 49), 60 | bgWhite: init(47, 49), 61 | blackBright: init(90, 39), 62 | redBright: init(91, 39), 63 | greenBright: init(92, 39), 64 | yellowBright: init(93, 39), 65 | blueBright: init(94, 39), 66 | magentaBright: init(95, 39), 67 | cyanBright: init(96, 39), 68 | whiteBright: init(97, 39), 69 | bgBlackBright: init(100, 49), 70 | bgRedBright: init(101, 49), 71 | bgGreenBright: init(102, 49), 72 | bgYellowBright: init(103, 49), 73 | bgBlueBright: init(104, 49), 74 | bgMagentaBright: init(105, 49), 75 | bgCyanBright: init(106, 49), 76 | bgWhiteBright: init(107, 49) 77 | } 78 | -------------------------------------------------------------------------------- /core/dev-utils/formatWebpackMessages.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict'; 3 | 4 | // WARNING: this code is untranspiled and is used in browser too. 5 | // Please make sure any changes are in ES5 or contribute a Babel compile step. 6 | var colors = require('./colors') 7 | 8 | // Some custom utilities to prettify Webpack output. 9 | // This is quite hacky and hopefully won't be needed when Webpack fixes this. 10 | // https://github.com/webpack/webpack/issues/2878 11 | var friendlySyntaxErrorLabel = 'Syntax error:'; 12 | 13 | function isLikelyASyntaxError(message) { 14 | return message.indexOf(friendlySyntaxErrorLabel) !== -1; 15 | } 16 | 17 | // Cleans up webpack error messages. 18 | // eslint-disable-next-line no-unused-vars 19 | function formatMessage(message, isError) { 20 | var lines = message.split('\n'); 21 | 22 | if (lines.length > 2 && lines[1] === '') { 23 | // Remove extra newline. 24 | lines.splice(1, 1); 25 | } 26 | 27 | // Remove webpack-specific loader notation from filename. 28 | // Before: 29 | // ./~/css-loader!./~/postcss-loader!./src/App.css 30 | // After: 31 | // ./src/App.css 32 | if (lines[0].lastIndexOf('!') !== -1) { 33 | lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1); 34 | } 35 | 36 | lines = lines.filter(function (line) { 37 | // Webpack adds a list of entry points to warning messages: 38 | // @ ./src/index.js 39 | // @ multi react-scripts/~/react-dev-utils/webpackHotDevClient.js ... 40 | // It is misleading (and unrelated to the warnings) so we clean it up. 41 | // It is only useful for syntax errors but we have beautiful frames for them. 42 | return line.indexOf(' @ ') !== 0; 43 | }); 44 | 45 | // line #0 is filename 46 | // line #1 is the main error message 47 | if (!lines[0] || !lines[1]) { 48 | return lines.join('\n'); 49 | } 50 | 51 | // Cleans up verbose "module not found" messages for files and packages. 52 | if (lines[1].indexOf('Module not found: ') === 0) { 53 | lines = [lines[0], 54 | // Clean up message because "Module not found: " is descriptive enough. 55 | lines[1].replace('Cannot resolve \'file\' or \'directory\' ', '').replace('Cannot resolve module ', '').replace('Error: ', '').replace('[CaseSensitivePathsPlugin] ', '')]; 56 | } 57 | 58 | // Cleans up syntax error messages. 59 | if (lines[1].indexOf('Module build failed: ') === 0) { 60 | lines[1] = lines[1].replace('Module build failed: SyntaxError:', friendlySyntaxErrorLabel); 61 | } 62 | 63 | // Clean up export errors. 64 | // TODO: we should really send a PR to Webpack for this. 65 | var exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/; 66 | if (lines[1].match(exportError)) { 67 | lines[1] = lines[1].replace(exportError, '$1 \'$4\' does not contain an export named \'$3\'.'); 68 | } 69 | 70 | lines[0] = colors.inverse(lines[0]); 71 | 72 | // Reassemble the message. 73 | message = lines.map(function (line) { 74 | if (line.indexOf('vue-template-compiler must be installed as a peer dependency') > -1) { 75 | return 'You need to install "vue-template-compiler" alongside "vue" in your project.' 76 | } 77 | return line 78 | }).join('\n'); 79 | // Internal stacks are generally useless so we strip them... with the 80 | // exception of: 81 | // 1: stacks containing `webpack:` because they're normally 82 | // from user code generated by WebPack. For more information see 83 | // https://github.com/facebookincubator/create-react-app/pull/1050 84 | // 2: from eval-loader 85 | var isEvalLoaderError = /webpack\/eval-loader\.js/.exec(lines[1]) 86 | if (!isEvalLoaderError) { 87 | message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, ''); // at ... ...:x:y 88 | } 89 | 90 | return message.trim(); 91 | } 92 | 93 | function formatWebpackMessages(json) { 94 | var formattedErrors = json.errors.map(function (message) { 95 | return formatMessage(message, true); 96 | }); 97 | var formattedWarnings = json.warnings.map(function (message) { 98 | return formatMessage(message, false); 99 | }); 100 | var result = { 101 | errors: formattedErrors, 102 | warnings: formattedWarnings 103 | }; 104 | if (result.errors.some(isLikelyASyntaxError)) { 105 | // If there are any syntax errors, show just them. 106 | // This prevents a confusing ESLint parsing error 107 | // preceding a much more useful Babel syntax error. 108 | result.errors = result.errors.filter(isLikelyASyntaxError); 109 | } 110 | return result; 111 | } 112 | 113 | module.exports = formatWebpackMessages; 114 | -------------------------------------------------------------------------------- /core/dev-utils/launchEditorEndpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = '/__open-in-editor' 2 | -------------------------------------------------------------------------------- /core/dev-utils/open.js: -------------------------------------------------------------------------------- 1 | module.exports = require('open') 2 | -------------------------------------------------------------------------------- /core/dev-utils/openBrowser.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict'; 3 | 4 | var execSync = require('child_process').execSync; 5 | var spawn = require('cross-spawn'); 6 | var open = require('./open'); 7 | var colors = require('./colors'); 8 | 9 | // https://github.com/sindresorhus/open#app 10 | var OSX_CHROME = 'google chrome'; 11 | 12 | const Actions = Object.freeze({ 13 | NONE: 0, 14 | BROWSER: 1, 15 | SCRIPT: 2, 16 | }); 17 | 18 | function getBrowserEnv() { 19 | // Attempt to honor this environment variable. 20 | // It is specific to the operating system. 21 | // See https://github.com/sindresorhus/open#app for documentation. 22 | const value = process.env.BROWSER; 23 | let action; 24 | if (!value) { 25 | // Default. 26 | action = Actions.BROWSER; 27 | } else if (value.toLowerCase().endsWith('.js')) { 28 | action = Actions.SCRIPT; 29 | } else if (value.toLowerCase() === 'none') { 30 | action = Actions.NONE; 31 | } else { 32 | action = Actions.BROWSER; 33 | } 34 | return { action, value }; 35 | } 36 | 37 | function executeNodeScript(scriptPath, url) { 38 | const extraArgs = process.argv.slice(2); 39 | const child = spawn('node', [scriptPath, ...extraArgs, url], { 40 | stdio: 'inherit', 41 | }); 42 | child.on('close', code => { 43 | if (code !== 0) { 44 | console.log(); 45 | console.log( 46 | colors.red( 47 | 'The script specified as BROWSER environment variable failed.' 48 | ) 49 | ); 50 | console.log(colors.cyan(scriptPath) + ' exited with code ' + code + '.'); 51 | console.log(); 52 | return; 53 | } 54 | }); 55 | return true; 56 | } 57 | 58 | function startBrowserProcess(browser, url) { 59 | // If we're on OS X, the user hasn't specifically 60 | // requested a different browser, we can try opening 61 | // Chrome with AppleScript. This lets us reuse an 62 | // existing tab when possible instead of creating a new one. 63 | const shouldTryOpenChromeWithAppleScript = 64 | process.platform === 'darwin' && 65 | (typeof browser !== 'string' || browser === OSX_CHROME); 66 | 67 | if (shouldTryOpenChromeWithAppleScript) { 68 | try { 69 | // Try our best to reuse existing tab 70 | // on OS X Google Chrome with AppleScript 71 | execSync('ps cax | grep "Google Chrome"'); 72 | execSync('osascript openChrome.applescript "' + encodeURI(url) + '"', { 73 | cwd: __dirname, 74 | stdio: 'ignore', 75 | }); 76 | return true; 77 | } catch (err) { 78 | // Ignore errors. 79 | } 80 | } 81 | 82 | // Another special case: on OS X, check if BROWSER has been set to "open". 83 | // In this case, instead of passing `open` to `open` (which won't work), 84 | // just ignore it (thus ensuring the intended behavior, i.e. opening the system browser): 85 | // https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768 86 | if (process.platform === 'darwin' && browser === 'open') { 87 | browser = undefined; 88 | } 89 | 90 | // Fallback to open 91 | // (It will always open new tab) 92 | try { 93 | var options = { app: browser }; 94 | open(url, options).catch(() => {}); // Prevent `unhandledRejection` error. 95 | return true; 96 | } catch (err) { 97 | return false; 98 | } 99 | } 100 | 101 | /** 102 | * Reads the BROWSER evironment variable and decides what to do with it. Returns 103 | * true if it opened a browser or ran a node.js script, otherwise false. 104 | */ 105 | function openBrowser(url) { 106 | const { action, value } = getBrowserEnv(); 107 | switch (action) { 108 | case Actions.NONE: 109 | // Special case: BROWSER="none" will prevent opening completely. 110 | return false; 111 | case Actions.SCRIPT: 112 | return executeNodeScript(value, url); 113 | case Actions.BROWSER: 114 | return startBrowserProcess(value, url); 115 | default: 116 | throw new Error('Not implemented.'); 117 | } 118 | } 119 | 120 | module.exports = openBrowser; 121 | -------------------------------------------------------------------------------- /core/dev-utils/openChrome.applescript: -------------------------------------------------------------------------------- 1 | (* 2 | Copyright (c) 2015-present, Facebook, Inc. 3 | This source code is licensed under the MIT license found in the 4 | LICENSE file in the root directory of this source tree. 5 | *) 6 | 7 | property targetTab: null 8 | property targetTabIndex: -1 9 | property targetWindow: null 10 | 11 | on run argv 12 | set theURL to item 1 of argv 13 | 14 | tell application "Chrome" 15 | 16 | if (count every window) = 0 then 17 | make new window 18 | end if 19 | 20 | -- 1: Looking for tab running debugger 21 | -- then, Reload debugging tab if found 22 | -- then return 23 | set found to my lookupTabWithUrl(theURL) 24 | if found then 25 | set targetWindow's active tab index to targetTabIndex 26 | tell targetTab to reload 27 | tell targetWindow to activate 28 | set index of targetWindow to 1 29 | return 30 | end if 31 | 32 | -- 2: Looking for Empty tab 33 | -- In case debugging tab was not found 34 | -- We try to find an empty tab instead 35 | set found to my lookupTabWithUrl("chrome://newtab/") 36 | if found then 37 | set targetWindow's active tab index to targetTabIndex 38 | set URL of targetTab to theURL 39 | tell targetWindow to activate 40 | return 41 | end if 42 | 43 | -- 3: Create new tab 44 | -- both debugging and empty tab were not found 45 | -- make a new tab with url 46 | tell window 1 47 | activate 48 | make new tab with properties {URL:theURL} 49 | end tell 50 | end tell 51 | end run 52 | 53 | -- Function: 54 | -- Lookup tab with given url 55 | -- if found, store tab, index, and window in properties 56 | -- (properties were declared on top of file) 57 | on lookupTabWithUrl(lookupUrl) 58 | tell application "Chrome" 59 | -- Find a tab with the given url 60 | set found to false 61 | set theTabIndex to -1 62 | repeat with theWindow in every window 63 | set theTabIndex to 0 64 | repeat with theTab in every tab of theWindow 65 | set theTabIndex to theTabIndex + 1 66 | if (theTab's URL as string) contains lookupUrl then 67 | -- assign tab, tab index, and window to properties 68 | set targetTab to theTab 69 | set targetTabIndex to theTabIndex 70 | set targetWindow to theWindow 71 | set found to true 72 | exit repeat 73 | end if 74 | end repeat 75 | 76 | if found then 77 | exit repeat 78 | end if 79 | end repeat 80 | end tell 81 | return found 82 | end lookupTabWithUrl -------------------------------------------------------------------------------- /core/dev-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/dev-utils", 3 | "version": "12.1.6", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "files": [ 8 | "*.js", 9 | "openChrome.applescript" 10 | ], 11 | "license": "MIT", 12 | "dependencies": { 13 | "address": "^1.0.3", 14 | "cross-spawn": "^7.0.2", 15 | "open": "^7.0.4", 16 | "react-error-overlay": "^6.0.7", 17 | "sockjs-client": "^1.1.5", 18 | "strip-ansi": "5.2.0" 19 | }, 20 | "xo": false 21 | } 22 | -------------------------------------------------------------------------------- /core/dev-utils/prepareProxy.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const url = require('url') 4 | const address = require('address') 5 | const colors = require('./colors') 6 | 7 | module.exports = function(proxy, appPublicFolder, debug) { 8 | // `proxy` lets you specify alternate servers for specific requests. 9 | if (!/^https?:\/\//.test(proxy)) { 10 | throw new Error( 11 | `When specified \`proxy\` as a string, it must start with http:// or https://` 12 | ) 13 | } 14 | 15 | // If proxy is specified, let it handle any request except for files in the public folder. 16 | function mayProxy(pathname) { 17 | const maybePublicPath = path.resolve(appPublicFolder, pathname.slice(1)) 18 | return !fs.existsSync(maybePublicPath) 19 | } 20 | 21 | let target 22 | if (process.platform === 'win32') { 23 | target = resolveLoopback(proxy) 24 | } else { 25 | target = proxy 26 | } 27 | return [ 28 | { 29 | target, 30 | logLevel: debug ? 'debug' : 'silent', 31 | // For single page apps, we generally want to fallback to /index.html. 32 | // However we also want to respect `proxy` for API calls. 33 | // So if `proxy` is specified as a string, we need to decide which fallback to use. 34 | // We use a heuristic: We want to proxy all the requests that are not meant 35 | // for static assets and as all the requests for static assets will be using 36 | // `GET` method, we can proxy all non-`GET` requests. 37 | // For `GET` requests, if request `accept`s text/html, we pick /index.html. 38 | // Modern browsers include text/html into `accept` header when navigating. 39 | // However API calls like `fetch()` won’t generally accept text/html. 40 | // If this heuristic doesn’t work well for you, use `src/setupProxy.js`. 41 | context(pathname, req) { 42 | // Explict context 43 | if (pathname.startsWith('/api/')) { 44 | return true 45 | } 46 | 47 | return ( 48 | req.method !== 'GET' || 49 | (mayProxy(pathname) && 50 | req.headers.accept && 51 | req.headers.accept.indexOf('text/html') === -1) 52 | ) 53 | }, 54 | onProxyReq: proxyReq => { 55 | // Browsers may send Origin headers even with same-origin 56 | // requests. To prevent CORS issues, we have to change 57 | // the Origin to match the target URL. 58 | if (proxyReq.getHeader('origin')) { 59 | proxyReq.setHeader('origin', target) 60 | } 61 | }, 62 | onError: onProxyError(target), 63 | secure: false, 64 | changeOrigin: true, 65 | ws: true, 66 | xfwd: true 67 | } 68 | ] 69 | } 70 | 71 | // We need to provide a custom onError function for httpProxyMiddleware. 72 | // It allows us to log custom error messages on the console. 73 | function onProxyError(proxy) { 74 | return (err, req, res) => { 75 | const host = req.headers && req.headers.host 76 | console.log( 77 | colors.red('Proxy error:') + 78 | ' Could not proxy request ' + 79 | colors.cyan(req.url) + 80 | ' from ' + 81 | colors.cyan(host) + 82 | ' to ' + 83 | colors.cyan(proxy) + 84 | '.' 85 | ) 86 | console.log( 87 | 'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' + 88 | colors.cyan(err.code) + 89 | ').' 90 | ) 91 | console.log() 92 | 93 | // And immediately send the proper error response to the client. 94 | // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side. 95 | if (res.writeHead && !res.headersSent) { 96 | res.writeHead(500) 97 | } 98 | res.end( 99 | 'Proxy error: Could not proxy request ' + 100 | req.url + 101 | ' from ' + 102 | host + 103 | ' to ' + 104 | proxy + 105 | ' (' + 106 | err.code + 107 | ').' 108 | ) 109 | } 110 | } 111 | 112 | function resolveLoopback(proxy) { 113 | const o = url.parse(proxy) 114 | o.host = undefined 115 | if (o.hostname !== 'localhost') { 116 | return proxy 117 | } 118 | // Unfortunately, many languages (unlike node) do not yet support IPv6. 119 | // This means even though localhost resolves to ::1, the application 120 | // must fall back to IPv4 (on 127.0.0.1). 121 | // We can re-enable this in a few years. 122 | /* try { 123 | o.hostname = address.ipv6() ? '::1' : '127.0.0.1'; 124 | } catch (_ignored) { 125 | o.hostname = '127.0.0.1'; 126 | } */ 127 | 128 | try { 129 | // Check if we're on a network; if we are, chances are we can resolve 130 | // localhost. Otherwise, we can just be safe and assume localhost is 131 | // IPv4 for maximum compatibility. 132 | if (!address.ip()) { 133 | o.hostname = '127.0.0.1' 134 | } 135 | } catch (_) { 136 | o.hostname = '127.0.0.1' 137 | } 138 | return url.format(o) 139 | } 140 | -------------------------------------------------------------------------------- /core/dev-utils/prettyBytes.js: -------------------------------------------------------------------------------- 1 | // Takens from https://github.com/sindresorhus/pretty-bytes/blob/master/index.js 2 | 3 | const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 4 | 5 | /* 6 | Formats the given number using `Number#toLocaleString`. 7 | - If locale is a string, the value is expected to be a locale-key (for example: `de`). 8 | - If locale is true, the system default locale is used for translation. 9 | - If no value for locale is specified, the number is returned unmodified. 10 | */ 11 | const toLocaleString = (number, locale) => { 12 | let result = number 13 | if (typeof locale === 'string') { 14 | result = number.toLocaleString(locale) 15 | } else if (locale === true) { 16 | result = number.toLocaleString() 17 | } 18 | 19 | return result 20 | } 21 | 22 | module.exports = (number, options) => { 23 | if (!Number.isFinite(number)) { 24 | throw new TypeError( 25 | `Expected a finite number, got ${typeof number}: ${number}` 26 | ) 27 | } 28 | 29 | options = Object.assign({}, options) 30 | 31 | if (options.signed && number === 0) { 32 | return ' 0 B' 33 | } 34 | 35 | const isNegative = number < 0 36 | const prefix = isNegative ? '-' : options.signed ? '+' : '' 37 | 38 | if (isNegative) { 39 | number = -number 40 | } 41 | 42 | if (number < 1) { 43 | const numberString = toLocaleString(number, options.locale) 44 | return prefix + numberString + ' B' 45 | } 46 | 47 | const exponent = Math.min( 48 | Math.floor(Math.log10(number) / 3), 49 | UNITS.length - 1 50 | ) 51 | number = Number((number / 1000 ** exponent).toPrecision(3)) 52 | const numberString = toLocaleString(number, options.locale) 53 | 54 | const unit = UNITS[exponent] 55 | 56 | return prefix + numberString + ' ' + unit 57 | } 58 | -------------------------------------------------------------------------------- /core/dev-utils/printServeMessage.js: -------------------------------------------------------------------------------- 1 | const url = require('url') 2 | const address = require('address') 3 | const colors = require('./colors') 4 | const prettyBytes = require('./prettyBytes') 5 | 6 | module.exports = ({ 7 | https, 8 | host, 9 | port, 10 | expectedPort, 11 | open, 12 | isFirstBuild, 13 | publicUrl 14 | }) => { 15 | const ip = address.ip() 16 | 17 | const protocol = https ? 'https' : 'http' 18 | const isUnspecifiedHost = host === '0.0.0.0' || host === '::' 19 | const prettyHost = isUnspecifiedHost ? 'localhost' : host 20 | const { heapUsed } = process.memoryUsage() 21 | 22 | const urlPort = colors.bold(port) 23 | const urlPath = publicUrl === '/' ? '' : url.resolve('/', publicUrl) 24 | 25 | console.log() 26 | console.log( 27 | `Local: ${protocol}://${prettyHost}:${urlPort}${urlPath}` 28 | ) 29 | console.log(`On Your Network: ${protocol}://${ip}:${urlPort}${urlPath}`) 30 | console.log() 31 | if (expectedPort && expectedPort !== port) { 32 | console.log(colors.yellow(`> port ${expectedPort} is used!`)) 33 | } 34 | console.log(colors.dim(`> ${prettyBytes(heapUsed)} memory used`)) 35 | console.log() 36 | 37 | if (open && isFirstBuild) { 38 | require('./openBrowser')(`${protocol}://${prettyHost}:${port}${urlPath}`) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/dev-utils/refreshOverlayInterop.js: -------------------------------------------------------------------------------- 1 | const { 2 | dismissRuntimeErrors, 3 | reportRuntimeError 4 | } = require('react-error-overlay') 5 | 6 | module.exports = { 7 | clearRuntimeErrors: dismissRuntimeErrors, 8 | handleRuntimeError: reportRuntimeError 9 | } 10 | -------------------------------------------------------------------------------- /core/dev-utils/runCompiler.js: -------------------------------------------------------------------------------- 1 | module.exports = compiler => 2 | new Promise((resolve, reject) => { 3 | compiler.run((err, stats) => { 4 | if (err) return reject(err) 5 | resolve(stats) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /core/dev-utils/skipServiceWorker.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resetScript = ` 4 | self.addEventListener('install', function(e) { 5 | self.skipWaiting() 6 | }) 7 | 8 | self.addEventListener('activate', function(e) { 9 | self.registration 10 | .unregister() 11 | .then(function() { 12 | return self.clients.matchAll() 13 | }) 14 | .then(function(clients) { 15 | clients.forEach(client => client.navigate(client.url)) 16 | }) 17 | }) 18 | 19 | ` 20 | 21 | // Express-like middleware 22 | module.exports = swPath => (req, res, next) => { 23 | if (req.url === path.join('/', swPath || 'service-worker.js')) { 24 | res.setHeader('Content-Type', 'text/javascript') 25 | res.send(resetScript) 26 | } else { 27 | next() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/logger/index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | 3 | class Logger { 4 | constructor(options) { 5 | this.setOptions(options) 6 | } 7 | 8 | setOptions(options) { 9 | this.options = Object.assign({}, this.options, options) 10 | } 11 | 12 | log(...args) { 13 | console.log( 14 | ...args.map(arg => { 15 | return typeof arg === 'function' ? arg() : arg 16 | }) 17 | ) 18 | } 19 | 20 | debug(...args) { 21 | if (!this.options.debug) { 22 | return 23 | } 24 | this.log(chalk.magenta('debug'), ...args) 25 | } 26 | 27 | error(...args) { 28 | this.log(chalk.red('error'), ...args) 29 | process.exitCode = process.exitCode || 1 30 | } 31 | 32 | success(...args) { 33 | this.log(chalk.green('success'), ...args) 34 | } 35 | 36 | done(...args) { 37 | this.log( 38 | chalk.green(process.platform === 'win32' ? '√' : '✔'), 39 | ...args.map(arg => chalk.bold(arg)) 40 | ) 41 | } 42 | 43 | warn(...args) { 44 | this.log(chalk.yellow('warning'), ...args) 45 | process.exitCode = process.exitCode || 1 46 | } 47 | 48 | tip(...args) { 49 | this.log(chalk.cyan('tip'), ...args) 50 | } 51 | } 52 | 53 | module.exports = new Logger() 54 | -------------------------------------------------------------------------------- /core/logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/logger", 3 | "version": "12.0.0", 4 | "files": [ 5 | "index.js" 6 | ], 7 | "main": "index.js", 8 | "publishConfig": { 9 | "access": "public" 10 | }, 11 | "dependencies": { 12 | "chalk": "^2.4.1" 13 | }, 14 | "xo": false 15 | } 16 | -------------------------------------------------------------------------------- /core/poi/README.md: -------------------------------------------------------------------------------- 1 | # Poi 2 | 3 | Check out https://poi.js.org 4 | -------------------------------------------------------------------------------- /core/poi/__test__/__snapshots__/format.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`cjs-format-cli 1`] = ` 4 | Array [ 5 | "dist/index.js", 6 | "dist/index.js.map", 7 | "index.js", 8 | ] 9 | `; 10 | 11 | exports[`cjs-format-config 1`] = ` 12 | Array [ 13 | "dist/index.js", 14 | "dist/index.js.map", 15 | "index.js", 16 | "poi.config.js", 17 | ] 18 | `; 19 | 20 | exports[`umd-format-cli 1`] = ` 21 | Array [ 22 | "dist/index.html", 23 | "dist/index.js", 24 | "dist/index.js.map", 25 | "index.js", 26 | ] 27 | `; 28 | 29 | exports[`umd-format-config 1`] = ` 30 | Array [ 31 | "dist/index.html", 32 | "dist/index.js", 33 | "dist/index.js.map", 34 | "index.js", 35 | "poi.config.js", 36 | ] 37 | `; 38 | -------------------------------------------------------------------------------- /core/poi/__test__/format.test.js: -------------------------------------------------------------------------------- 1 | const createProject = require('@poi/test-utils/createProject') 2 | 3 | test('cjs-format-cli', async () => { 4 | const project = await createProject({ name: 'cjs-format-cli' }) 5 | await project.write('index.js', 'export default 123') 6 | await project.run('poi --format cjs') 7 | expect(project.files).toMatchSnapshot() 8 | expect(project.require('dist/index.js')).toEqual({ default: 123 }) 9 | }) 10 | 11 | test('cjs-format-config', async () => { 12 | const project = await createProject({ name: 'cjs-format-config' }) 13 | await Promise.all([ 14 | project.write('index.js', 'export default 123'), 15 | project.write('poi.config.js', 'exports.output = { format: "cjs" }') 16 | ]) 17 | await project.run('poi') 18 | expect(project.files).toMatchSnapshot() 19 | expect(project.require('dist/index.js')).toEqual({ default: 123 }) 20 | }) 21 | 22 | test('umd-format-cli', async () => { 23 | const project = await createProject({ name: 'umd-format-cli' }) 24 | await project.write('index.js', 'export default 123') 25 | await project.run('poi --format umd --module-name Foo') 26 | expect(project.files).toMatchSnapshot() 27 | expect(project.require('dist/index.js')).toEqual({ default: 123 }) 28 | }) 29 | 30 | test('umd-format-config', async () => { 31 | const project = await createProject({ name: 'umd-format-config' }) 32 | await Promise.all([ 33 | project.write('index.js', 'export default 123'), 34 | project.write( 35 | 'poi.config.js', 36 | 'exports.output = { format: "umd", moduleName: "Foo" }' 37 | ) 38 | ]) 39 | await project.run('poi') 40 | expect(project.files).toMatchSnapshot() 41 | expect(project.require('dist/index.js')).toEqual({ default: 123 }) 42 | }) 43 | -------------------------------------------------------------------------------- /core/poi/babel.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/babel/preset') 2 | -------------------------------------------------------------------------------- /core/poi/bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // eslint-disable-next-line import/no-unassigned-import 3 | require('v8-compile-cache') 4 | const Poi = require('..') 5 | 6 | process.on('unhandledRejection', error => { 7 | console.error(error) 8 | process.exit(1) 9 | }) 10 | 11 | async function main() { 12 | try { 13 | const poi = new Poi() 14 | await poi.run() 15 | } catch (error) { 16 | require('../lib/utils/spinner').stop() 17 | if (error.poi) { 18 | if (!error.dismiss) { 19 | require('@poi/logger').error(error.message) 20 | } 21 | } else { 22 | console.error(error.stack) 23 | } 24 | process.exit(1) 25 | } 26 | } 27 | 28 | main() 29 | -------------------------------------------------------------------------------- /core/poi/lib/Hooks.js: -------------------------------------------------------------------------------- 1 | module.exports = class Hooks { 2 | constructor() { 3 | this.hooks = new Map() 4 | } 5 | 6 | add(name, fn) { 7 | const hooks = this.get(name) 8 | hooks.add(fn) 9 | this.hooks.set(name, hooks) 10 | } 11 | 12 | get(name) { 13 | return this.hooks.get(name) || new Set() 14 | } 15 | 16 | invoke(name, ...args) { 17 | for (const hook of this.get(name)) { 18 | hook(...args) 19 | } 20 | } 21 | 22 | async invokePromise(name, ...args) { 23 | for (const hook of this.get(name)) { 24 | await hook(...args) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/poi/lib/WebpackUtils.js: -------------------------------------------------------------------------------- 1 | module.exports = class WebpackUtils { 2 | constructor(api) { 3 | this.api = api 4 | } 5 | 6 | get envs() { 7 | const envs = { 8 | NODE_ENV: this.api.mode === 'production' ? 'production' : 'development' 9 | } 10 | 11 | // Collect variables starting with `POI_APP_` from `process.env` 12 | for (const name of Object.keys(process.env)) { 13 | if (name.startsWith('POI_APP_')) { 14 | envs[name] = process.env[name] 15 | } 16 | } 17 | 18 | Object.assign(envs, this.api.config.envs, { 19 | PUBLIC_URL: this.api.config.output.publicUrl 20 | }) 21 | 22 | return envs 23 | } 24 | 25 | get constants() { 26 | return Object.assign({}, this.api.config.constants) 27 | } 28 | 29 | get CopyPlugin() { 30 | return require('copy-webpack-plugin') 31 | } 32 | 33 | addParallelSupport(rule) { 34 | if (this.api.config.parallel) { 35 | rule.use('thread-loader').loader(require.resolve('thread-loader')) 36 | } 37 | 38 | return this 39 | } 40 | 41 | addCacheSupport(rule, getCacheConfig) { 42 | if (this.api.config.cache) { 43 | rule 44 | .use('cache-loader') 45 | .loader(require.resolve('cache-loader')) 46 | .options(getCacheConfig()) 47 | } 48 | 49 | return this 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/poi/lib/babel/preset.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const merge = require('lodash.merge') 3 | 4 | const env = process.env.BABEL_ENV || process.env.NODE_ENV 5 | const isTest = env === 'test' 6 | const isDevelopment = env === 'development' 7 | 8 | const validateBoolOption = (name, value, defaultValue) => { 9 | if (typeof value === 'undefined') { 10 | value = defaultValue 11 | } 12 | 13 | if (typeof value !== 'boolean') { 14 | throw new TypeError(`Poi babel preset: '${name}' option must be a boolean.`) 15 | } 16 | 17 | return value 18 | } 19 | 20 | module.exports = ( 21 | context, 22 | { 23 | jsx = process.env.POI_JSX || 'react', 24 | jsxPragmaFrag, 25 | flow, 26 | typescript, 27 | env, 28 | namedImports = process.env.POI_NAMED_IMPORTS, 29 | reactRefresh = process.env.POI_REACT_REFRESH 30 | } = {} 31 | ) => { 32 | if (typeof namedImports === 'string') { 33 | namedImports = JSON.parse(namedImports) 34 | } 35 | if (typeof reactRefresh === 'string') { 36 | reactRefresh = reactRefresh === 'true' 37 | } 38 | 39 | const isVueJSX = jsx === 'vue' 40 | const isReactJSX = jsx === 'react' 41 | const isPreactJSX = jsx === 'preact' 42 | 43 | // Enable flow and typescript by default at the same time 44 | // typescript transforms will only be applied to .ts .tsx files 45 | const isFlowEnabled = validateBoolOption('flow', flow, true) 46 | const isTypeScriptEnabled = validateBoolOption('typescript', typescript, true) 47 | 48 | const isReactRefreshEnabled = isDevelopment && reactRefresh 49 | 50 | const presets = [ 51 | [ 52 | require('@babel/preset-env'), 53 | Object.assign( 54 | { 55 | modules: isTest ? 'commonjs' : false, 56 | targets: isTest 57 | ? { 58 | node: 'current' 59 | } 60 | : { 61 | ie: 9 62 | } 63 | }, 64 | env 65 | ) 66 | ], 67 | !isVueJSX && [ 68 | require('@babel/preset-react'), 69 | { 70 | pragma: isReactJSX ? 'React.createElement' : isPreactJSX ? 'h' : jsx, 71 | pragmaFrag: isReactJSX 72 | ? 'React.Fragment' 73 | : isPreactJSX 74 | ? 'Fragment' 75 | : jsxPragmaFrag 76 | } 77 | ], 78 | isTypeScriptEnabled && require('@babel/preset-typescript') 79 | ].filter(Boolean) 80 | 81 | const plugins = [ 82 | // Strip flow types before any other transform, emulating the behavior 83 | // order as-if the browser supported all of the succeeding features 84 | isFlowEnabled && require('@babel/plugin-transform-flow-strip-types'), 85 | // JSX config 86 | isVueJSX && require('@babel/plugin-syntax-jsx'), 87 | isVueJSX && require('babel-plugin-transform-vue-jsx'), 88 | // stage-3 features 89 | require('@babel/plugin-syntax-dynamic-import'), 90 | [ 91 | require('@babel/plugin-proposal-class-properties'), 92 | { 93 | // Enable loose mode to use assignment instead of defineProperty 94 | loose: true 95 | } 96 | ], 97 | [ 98 | require('@babel/plugin-proposal-object-rest-spread'), 99 | { 100 | useBuiltIns: true 101 | } 102 | ], 103 | [ 104 | require('babel-plugin-assets-named-imports'), 105 | { 106 | loaderMap: merge( 107 | { 108 | svg: { 109 | ReactComponent: '!@svgr/webpack?-prettier![path]' 110 | }, 111 | md: { 112 | ReactComponent: `!babel-loader?${JSON.stringify({ 113 | babelrc: false, 114 | configFile: false, 115 | presets: [__filename] 116 | })}!@mdx-js/loader![path]` 117 | } 118 | }, 119 | namedImports 120 | ) 121 | } 122 | ], 123 | require('babel-plugin-macros'), 124 | [ 125 | require('@babel/plugin-transform-runtime'), 126 | { 127 | helpers: false, 128 | regenerator: true, 129 | absoluteRuntime: path.dirname( 130 | require.resolve('@babel/runtime/package.json') 131 | ) 132 | } 133 | ], 134 | require('@babel/plugin-proposal-optional-chaining'), 135 | isReactRefreshEnabled && require('react-refresh/babel') 136 | ].filter(Boolean) 137 | 138 | return { 139 | presets, 140 | plugins 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/command-options.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:shared-options' 2 | 3 | exports.cli = ({ command, isProd }) => { 4 | command.option('-d, --out-dir ', 'Output directory', { 5 | default: 'dist' 6 | }) 7 | 8 | command.option('--no-progress', 'Disable default progress bar') 9 | 10 | if (isProd) { 11 | command.option('--source-map', 'Enable source map') 12 | } else { 13 | command.option('--no-source-map', 'Disable source map') 14 | } 15 | 16 | command.option('--parallel', 'Enable multicore compilation (experimental)') 17 | 18 | command.option('--no-cache', 'Disable compilation caching') 19 | 20 | command.option('--public-url ', 'Set the public URL to serve on', { 21 | default: '/' 22 | }) 23 | command.option('--public-folder ', 'Use a public folder', { 24 | default: 'public' 25 | }) 26 | command.option('--no-public-folder', 'Disable public folder') 27 | command.option('--target ', 'Target environment', { 28 | default: 'web' 29 | }) 30 | command.option('--format ', 'Output format', { default: 'iife' }) 31 | command.option('--module-name ', 'Module name for "umd" format') 32 | command.option('--file-names ', 'Customize output filenames') 33 | command.option('--no-clean', `Don't clean output directory before bundling`) 34 | command.option('--html ', 'Configure generated HTML file') 35 | command.option('--no-html', `Don't generate HTML file`) 36 | command.option('--no-clear-console', `Don't clear console`) 37 | 38 | if (isProd) { 39 | command.option('--no-minimize', 'Disable minimization') 40 | } else { 41 | command.option('--minimize', 'Minimize output') 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-babel.js: -------------------------------------------------------------------------------- 1 | const logger = require('@poi/logger') 2 | 3 | exports.name = 'builtin:config-babel' 4 | 5 | exports.cli = ({ command }) => { 6 | command 7 | .option('--jsx ', 'Set JSX syntax', { 8 | default: 'react' 9 | }) 10 | .option('--no-babelrc', `Disable .babelrc files`) 11 | .option('--no-babel-config-file', `Disable babel.config.js`) 12 | .option( 13 | '--named-imports ', 14 | 'Conver specific named imports to use custom loaders' 15 | ) 16 | } 17 | 18 | exports.apply = api => { 19 | api.hook('createWebpackChain', config => { 20 | const { transpileModules, jsx, namedImports } = api.config.babel || {} 21 | 22 | process.env.POI_JSX = jsx 23 | if (namedImports) { 24 | process.env.POI_NAMED_IMPORTS = 25 | typeof namedImports === 'string' 26 | ? namedImports 27 | : JSON.stringify(namedImports) 28 | } 29 | 30 | // Handle .mjs 31 | config.module 32 | .rule('mjs') 33 | .test(/\.mjs$/) 34 | .type('javascript/auto') 35 | 36 | // Handle other js files 37 | const rule = config.module.rule('js') 38 | 39 | rule 40 | .test([/\.m?js$/, /\.jsx$/, /\.ts$/, /\.tsx$/]) 41 | .include.add(filepath => { 42 | // Ensure there're no back slashes 43 | filepath = filepath.replace(/\\/g, '/') 44 | // Transpile everthing outside node_modules 45 | if (!/node_modules/.test(filepath)) { 46 | return true 47 | } 48 | if (transpileModules) { 49 | const shouldTranspile = [] 50 | .concat(transpileModules) 51 | .some(condition => { 52 | return typeof condition === 'string' 53 | ? filepath.includes(`/node_modules/${condition}/`) 54 | : filepath.match(condition) 55 | }) 56 | if (shouldTranspile) { 57 | logger.debug(`Babel is transpiling addtional file "${filepath}"`) 58 | return true 59 | } 60 | } 61 | return false 62 | }) 63 | 64 | api.webpackUtils.addParallelSupport(rule) 65 | 66 | rule 67 | .use('babel-loader') 68 | .loader(require.resolve('../webpack/babel-loader')) 69 | .options({ 70 | cacheDirectory: api.config.cache, 71 | cacheCompression: api.isProd, 72 | cacheIdentifier: `jsx:${process.env.POI_JSX}::namedImports:${ 73 | process.env.POI_NAMED_IMPORTS 74 | }`, 75 | babelrc: api.config.babel.babelrc, 76 | configFile: api.config.babel.configFile 77 | }) 78 | }) 79 | } 80 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-electron.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-electron' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | if (api.config.target !== 'electron') return 6 | 7 | // Force public URL 8 | config.output.publicPath('./') 9 | config.plugin('envs').tap(([options]) => [ 10 | Object.assign(options, { 11 | PUBLIC_URL: JSON.stringify('./') 12 | }) 13 | ]) 14 | 15 | config.target('electron-renderer') 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-eval.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-eval' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | config.module 6 | .rule('eval') 7 | .test([/\.eval\.js$/, /\.eval\.ts$/]) 8 | .type('json') 9 | .post() 10 | .use('eval-loader') 11 | .loader(require.resolve('../webpack/eval-loader')) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-font.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-font' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | config.module 6 | .rule('font') 7 | .test(/\.(eot|otf|ttf|woff|woff2)(\?.*)?$/) 8 | .use('file-loader') 9 | .loader(require.resolve('file-loader')) 10 | .options({ 11 | name: api.config.output.fileNames.font 12 | }) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-image.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-image' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | const filename = api.config.output.fileNames.image 6 | 7 | config.module 8 | .rule('image') 9 | .test([/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.webp$/]) 10 | .use('url-loader') 11 | .loader(require.resolve('url-loader')) 12 | .options({ 13 | name: filename, 14 | // inline the file if smaller than this size 15 | limit: api.config.assets.inlineImageMaxSize 16 | }) 17 | 18 | config.module 19 | .rule('svg') 20 | .test(/\.(svg)(\?.*)?$/) 21 | .use('file-loader') 22 | // SVG files use file-loader directly, why? 23 | // See https://github.com/facebookincubator/create-react-app/pull/1180 24 | .loader(require.resolve('file-loader')) 25 | .options({ 26 | name: filename 27 | }) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-jsx-import.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-jsx-import' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | const { jsx } = api.config.babel 6 | if (jsx === 'preact') { 7 | // Automatically add `import { h, Fragment } from 'preact'` for free `h` and `Fragment` identifiers 8 | // In the module scope 9 | config.plugin('jsx-import').use(require('webpack').ProvidePlugin, [ 10 | { 11 | h: ['preact', 'h'], 12 | Fragment: ['preact', 'Fragment'] 13 | } 14 | ]) 15 | } else if (jsx === 'react') { 16 | // Automatically add `import React from 'preact'` for free `React` identifier 17 | // In the module scope 18 | config.plugin('jsx-import').use(require('webpack').ProvidePlugin, [ 19 | { 20 | React: 'react' 21 | } 22 | ]) 23 | } 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-misc-loaders.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-misc-loaders' 2 | 3 | exports.apply = api => { 4 | api.hook('createWebpackChain', config => { 5 | // GraphQL 6 | config.module 7 | .rule('graphql') 8 | .test(/\.(graphql|gql)$/) 9 | .use('graphql-tag') 10 | .loader('graphql-tag/loader') 11 | 12 | config.module 13 | .rule('toml') 14 | .test(/\.toml$/) 15 | .use('toml-loader') 16 | .loader('toml-loader') 17 | 18 | config.module 19 | .rule('yaml') 20 | .test(/\.ya?ml$/) 21 | .merge({ 22 | type: 'json' 23 | }) 24 | .use('yaml-loader') 25 | .loader('yaml-loader') 26 | 27 | // prettier-ignore 28 | config.module 29 | .rule('pug') 30 | .test([/\.pug$/, /\.jade$/]) 31 | // Pug inside Vue template is loaded as raw string 32 | .oneOf('vue-template') 33 | .resourceQuery(/^\?vue/) 34 | .use('pug-plain-loader') 35 | .loader('pug-plain-loader') 36 | .end() 37 | .end() 38 | // Pug inside js file is loaded as a compiled function 39 | .oneOf('normal') 40 | .use('pug-loader') 41 | .loader('pug-loader') 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-react-refresh.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-react-refresh' 2 | 3 | exports.cli = ({ command }) => { 4 | command.option('--react-refresh', 'Enable React Refresh') 5 | } 6 | 7 | exports.when = api => api.config.reactRefresh && api.mode === 'development' 8 | 9 | exports.apply = api => { 10 | api.hook('createWebpackChain', config => { 11 | process.env.POI_REACT_REFRESH = api.hasDependency('react') 12 | 13 | config 14 | .plugin('react-refresh') 15 | .use(require('@pmmmwh/react-refresh-webpack-plugin'), [ 16 | { 17 | overlay: { 18 | entry: require.resolve('@poi/dev-utils/hotDevClient'), 19 | // The expected exports are slightly different from what the overlay exports, 20 | // so an interop is included here to enable feedback on module-level errors. 21 | module: require.resolve('@poi/dev-utils/refreshOverlayInterop'), 22 | // Since we ship a custom dev client and overlay integration, 23 | // the bundled socket handling logic can be eliminated. 24 | sockIntegration: false 25 | } 26 | } 27 | ]) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-reason.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:config-reason' 2 | 3 | exports.when = api => api.hasDependency('bs-platform') 4 | 5 | exports.apply = api => { 6 | api.hook('createWebpackChain', config => { 7 | config.module 8 | .rule('reason') 9 | .test(/\.(re|ml)$/) 10 | .use('reason-loader') 11 | .loader(require.resolve('../webpack/reason-loader')) 12 | .options({ 13 | watch: api.cli.options.serve || api.cli.options.watch 14 | }) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-vue.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const resolveFrom = require('resolve-from') 3 | const logger = require('@poi/logger') 4 | const PoiError = require('../utils/PoiError') 5 | 6 | exports.name = 'builtin:config-vue' 7 | 8 | exports.apply = api => { 9 | api.hook('createWebpackChain', config => { 10 | const rule = config.module.rule('vue').test(/\.vue$/) 11 | 12 | const vueLoaderPath = path.dirname( 13 | api.localResolve('vue-loader/package.json') || 14 | require.resolve('vue-loader/package.json') 15 | ) 16 | const vueLoaderPkg = require(path.join(vueLoaderPath, 'package.json')) 17 | const vueLoaderMajorVersion = parseInt(vueLoaderPkg.version, 10) 18 | const isVue3 = vueLoaderMajorVersion >= 16 19 | 20 | if (isVue3 && vueLoaderPkg.version.includes('beta')) { 21 | logger.warn(`You are using the beta version of vue-loader, be aware!`) 22 | } 23 | 24 | const getCacheOptions = () => { 25 | if (isVue3) { 26 | const hasSFCCompiler = api.localResolve( 27 | '@vue/compiler-sfc/package.json' 28 | ) 29 | if (!hasSFCCompiler) { 30 | throw new PoiError( 31 | `Expect @vue/compiler-sfc to be installed in current project` 32 | ) 33 | } 34 | return api.getCacheConfig('vue-loader', { 35 | 'vue-loader': vueLoaderPkg.version, 36 | '@vue/compiler-sfc': hasSFCCompiler 37 | ? api.localRequire('@vue/compiler-sfc/package.json').version 38 | : null 39 | }) 40 | } 41 | 42 | const compilerPkg = require(resolveFrom( 43 | vueLoaderPath, 44 | '@vue/component-compiler-utils/package' 45 | )) 46 | return api.getCacheConfig('vue-loader', { 47 | 'vue-loader': vueLoaderPkg.version, 48 | '@vue/component-compiler-utils': compilerPkg.version, 49 | 'vue-template-compiler': api.localResolve( 50 | 'vue-template-compiler/package' 51 | ) 52 | ? api.localRequire('vue-template-compiler/package').version 53 | : null 54 | }) 55 | } 56 | 57 | api.webpackUtils.addCacheSupport(rule, getCacheOptions) 58 | 59 | rule 60 | .use('vue-loader') 61 | .loader(require.resolve(vueLoaderPath)) 62 | .options( 63 | Object.assign( 64 | { 65 | // TODO: error with thread-loader 66 | compiler: isVue3 67 | ? undefined 68 | : api.localRequire('vue-template-compiler') 69 | }, 70 | // For Vue templates 71 | api.config.cache && getCacheOptions() 72 | ) 73 | ) 74 | 75 | config.plugin('vue').use(require(vueLoaderPath).VueLoaderPlugin) 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/config-yarn-pnp.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:yarn-pnp' 2 | 3 | exports.when = api => 4 | api.pkg.data.installConfig && api.pkg.data.installConfig.pnp 5 | 6 | exports.apply = api => { 7 | api.hook('createWebpackChain', config => { 8 | const { apply, moduleLoader } = require('@poi/pnp-webpack-plugin') 9 | 10 | config.resolve.plugin('pnp').use( 11 | class PnpWebpackPlugin { 12 | apply(...args) { 13 | return apply(...args) 14 | } 15 | } 16 | ) 17 | 18 | config.resolveLoader.plugin('pnp').use( 19 | class PnpWebpackPlugin { 20 | apply(...args) { 21 | return moduleLoader(module).apply(...args) 22 | } 23 | } 24 | ) 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/eject-html.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | exports.name = 'eject-html' 4 | 5 | exports.cli = api => { 6 | api.cli 7 | .command('eject-html [out-file]', 'Eject the default HTML file') 8 | .option('--overwrite', 'Overwrite exiting file') 9 | .action(async (outFile = 'public/index.html', options) => { 10 | const fs = require('fs-extra') 11 | if ( 12 | !options.overwrite && 13 | (await fs.pathExists(api.resolveCwd(outFile))) 14 | ) { 15 | return api.logger.error( 16 | `${outFile} already existing, try --overwrite flag if you want to update it` 17 | ) 18 | } 19 | await fs.copy( 20 | path.join(__dirname, '../webpack/default-template.html'), 21 | api.resolveCwd(outFile) 22 | ) 23 | api.logger.done(`Ejected to ${outFile}`) 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /core/poi/lib/plugins/watch.js: -------------------------------------------------------------------------------- 1 | exports.name = 'builtin:watch' 2 | 3 | exports.cli = api => { 4 | const { command, args } = api 5 | 6 | command.option('-w, --watch', 'Watch and rebuild on file changes') 7 | 8 | if (!args.has('w') && !args.has('watch')) return 9 | 10 | command.action(() => { 11 | const compiler = api.createWebpackCompiler( 12 | api.createWebpackChain().toConfig() 13 | ) 14 | compiler.watch({}, err => { 15 | if (err) { 16 | api.logger.error(err) 17 | } 18 | }) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /core/poi/lib/utils/PoiError.js: -------------------------------------------------------------------------------- 1 | module.exports = class PoiError extends Error { 2 | constructor(message) { 3 | const options = typeof message === 'string' ? { message } : message 4 | super(options.message) 5 | this.dismiss = options.dismiss 6 | this.poi = true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/poi/lib/utils/WebpackChain.js: -------------------------------------------------------------------------------- 1 | const Chain = require('webpack-chain') 2 | const merge = require('webpack-merge') 3 | 4 | module.exports = class WebpackChain extends Chain { 5 | constructor({ configureWebpack, opts }) { 6 | super() 7 | this.configureWebpack = configureWebpack 8 | this.opts = opts 9 | } 10 | 11 | toConfig() { 12 | let config = super.toConfig() 13 | if (typeof this.configureWebpack === 'function') { 14 | config = this.configureWebpack(config, this.opts) || config 15 | } else if (typeof this.configureWebpack === 'object') { 16 | config = merge({}, config, this.configureWebpack) 17 | } 18 | return config 19 | } 20 | 21 | toString(options) { 22 | return Chain.toString(this.toConfig(), options) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/poi/lib/utils/__test__/plugins.test.js: -------------------------------------------------------------------------------- 1 | const { mergePlugins } = require('../plugins') 2 | 3 | test('merge', () => { 4 | expect( 5 | mergePlugins( 6 | [{ resolve: 'foo' }, { resolve: 'bar', options: { foo: 'bar' } }], 7 | [ 8 | { 9 | resolve: 'foo' 10 | }, 11 | { 12 | resolve: 'baz' 13 | } 14 | ] 15 | ) 16 | ).toEqual([ 17 | { resolve: 'foo' }, 18 | { resolve: 'bar', options: { foo: 'bar' } }, 19 | { 20 | resolve: 'baz' 21 | } 22 | ]) 23 | }) 24 | -------------------------------------------------------------------------------- /core/poi/lib/utils/createConfigLoader.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const Module = require('module') 4 | const colors = require('chalk') 5 | const JoyCon = require('joycon').default 6 | const PoiError = require('./PoiError') 7 | 8 | const rcLoader = { 9 | name: 'rc', 10 | test: /\.[a-z]+rc$/, 11 | loadSync(filePath) { 12 | return JSON.parse(fs.readFileSync(filePath, 'utf8')) 13 | } 14 | } 15 | 16 | const tsLoader = { 17 | name: 'ts', 18 | test: /\.ts$/, 19 | loadSync(filePath) { 20 | if (!Module._extensions['.ts']) { 21 | throw new PoiError( 22 | `Found ${path.relative( 23 | process.cwd(), 24 | filePath 25 | )}, try installing ${colors.bold( 26 | '`ts-node`' 27 | )} and using CLI flag ${colors.bold( 28 | '`-r ts-node/register`' 29 | )} to support .ts config files. If you don't need type checking, use ${colors.bold( 30 | '`-r ts-node/register/transpile-only`' 31 | )} instead.` 32 | ) 33 | } 34 | const result = require(filePath) 35 | return result.default || result 36 | } 37 | } 38 | 39 | module.exports = cwd => { 40 | const configLoader = new JoyCon({ cwd, stopDir: path.dirname(process.cwd()) }) 41 | 42 | configLoader.addLoader(rcLoader) 43 | configLoader.addLoader(tsLoader) 44 | 45 | return { 46 | load(opts, noCache) { 47 | if (noCache) { 48 | configLoader.clearCache() 49 | } 50 | return configLoader.loadSync(opts) 51 | }, 52 | resolve(opts, noCache) { 53 | if (noCache) { 54 | configLoader.clearCache() 55 | } 56 | return configLoader.resolveSync(opts) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/poi/lib/utils/getFileNames.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ useHash, format }) => { 2 | let res 3 | 4 | if (format === 'iife') { 5 | res = { 6 | js: useHash ? 'assets/js/[name].[chunkhash:8].js' : 'assets/js/[name].js', 7 | css: useHash 8 | ? 'assets/css/[name].[chunkhash:8].css' 9 | : 'assets/css/[name].css', 10 | font: useHash 11 | ? 'assets/fonts/[path][name].[hash:8].[ext]' 12 | : 'assets/fonts/[path][name].[ext]', 13 | image: useHash 14 | ? 'assets/images/[path][name].[hash:8].[ext]' 15 | : 'assets/images/[path][name].[ext]' 16 | } 17 | } else { 18 | res = { 19 | js: '[name].js', 20 | css: '[name].css', 21 | font: '[path][name].[ext]', 22 | image: '[path][name].[ext]' 23 | } 24 | } 25 | 26 | return res 27 | } 28 | -------------------------------------------------------------------------------- /core/poi/lib/utils/isLocalPath.js: -------------------------------------------------------------------------------- 1 | module.exports = v => /^[./]|(^[a-zA-Z]:)/.test(v) 2 | -------------------------------------------------------------------------------- /core/poi/lib/utils/loadEnvs.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const logger = require('@poi/logger') 3 | 4 | module.exports = (mode, dotenvPath) => { 5 | const dotenvFiles = [ 6 | `${dotenvPath}.${mode}.local`, 7 | `${dotenvPath}.${mode}`, 8 | // Don't include `.env.local` for `test` mode 9 | // since normally you expect tests to produce the same 10 | // results for everyone 11 | mode !== 'test' && `${dotenvPath}.local`, 12 | dotenvPath 13 | ].filter(Boolean) 14 | 15 | dotenvFiles.forEach(dotenvFile => { 16 | if (fs.existsSync(dotenvFile)) { 17 | logger.debug('Using env file:', dotenvFile) 18 | require('dotenv-expand')( 19 | require('dotenv').config({ 20 | path: dotenvFile 21 | }) 22 | ) 23 | } 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /core/poi/lib/utils/mergeConfig.js: -------------------------------------------------------------------------------- 1 | const merge = require('lodash.merge') 2 | 3 | module.exports = (config, cliConfig) => { 4 | const devServer = merge({}, config.devServer, cliConfig.devServer, { 5 | proxy: [] 6 | .concat((config.devServer && config.devServer.proxy) || []) 7 | .concat(cliConfig.devServer.proxy || []) 8 | }) 9 | return merge({}, config, cliConfig, { 10 | devServer 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /core/poi/lib/utils/parseArgs.js: -------------------------------------------------------------------------------- 1 | const cac = require('cac') 2 | 3 | module.exports = _args => { 4 | const cli = cac() 5 | const { args, options } = cli.parse(_args) 6 | 7 | return { 8 | get(name) { 9 | return options[name] 10 | }, 11 | 12 | has(name) { 13 | return this.get(name) !== undefined 14 | }, 15 | 16 | options, 17 | 18 | args 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/poi/lib/utils/plugins.js: -------------------------------------------------------------------------------- 1 | const resolveFrom = require('resolve-from') 2 | const logger = require('@poi/logger') 3 | const isLocalPath = require('./isLocalPath') 4 | const PoiError = require('./PoiError') 5 | 6 | const normalizePluginName = (name, cwd) => { 7 | if (isLocalPath(name)) return name 8 | 9 | // @poi/foo => @poi/plugin-foo 10 | // @my-org/hehe => @my-org/poi-plugin-hehe 11 | if (/^@[^/]+\//.test(name)) { 12 | return name.replace(/^@([^/]+)\/(poi-)?(plugin-)?/, (_, m1) => { 13 | return m1 === 'poi' ? `@poi/plugin-` : `@${m1}/poi-plugin-` 14 | }) 15 | } 16 | 17 | const prefixedName = name.replace(/^(poi-plugin-)?/, 'poi-plugin-') 18 | 19 | // if a prefixed name exists, use it directly 20 | if (resolveFrom.silent(cwd, prefixedName)) { 21 | return prefixedName 22 | } 23 | 24 | return name 25 | } 26 | 27 | exports.normalizePlugins = (plugins, cwd) => { 28 | return [].concat(plugins || []).map(v => { 29 | if (typeof v === 'string') { 30 | v = { resolve: v } 31 | } 32 | if (typeof v.resolve === 'string') { 33 | const pluginName = normalizePluginName(v.resolve, cwd) 34 | const resolvedPlugin = resolveFrom.silent(cwd, pluginName) 35 | if (!resolvedPlugin) { 36 | const message = `Cannot find plugin \`${pluginName}\` in your project` 37 | logger.error(message) 38 | logger.error(`Did you forget to install it?`) 39 | throw new PoiError({ 40 | message, 41 | dismiss: true 42 | }) 43 | } 44 | v = Object.assign({}, v, { 45 | resolve: resolvedPlugin 46 | }) 47 | } 48 | return v 49 | }) 50 | } 51 | 52 | exports.mergePlugins = (configPlugins, cliPlugins) => { 53 | return configPlugins.concat( 54 | cliPlugins.filter(cliPlugin => { 55 | return !configPlugins.find( 56 | configPlugin => configPlugin.resolve === cliPlugin.resolve 57 | ) 58 | }) 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /core/poi/lib/utils/spinner.js: -------------------------------------------------------------------------------- 1 | const ora = require('ora') 2 | 3 | module.exports = ora() 4 | -------------------------------------------------------------------------------- /core/poi/lib/webpack/PrintStatusPlugin.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const chalk = require('chalk') 3 | const textTable = require('text-table') 4 | const gzipSize = require('gzip-size') 5 | const formatWebpackMessages = require('@poi/dev-utils/formatWebpackMessages') 6 | const prettyBytes = require('@poi/dev-utils/prettyBytes') 7 | const logger = require('@poi/logger') 8 | const prettyTime = require('pretty-ms') 9 | 10 | class PrintStatusPlugin { 11 | constructor(opts = {}) { 12 | this.opts = opts 13 | } 14 | 15 | apply(compiler) { 16 | compiler.hooks.invalid.tap('show-rebuild-reason', file => { 17 | const d = new Date() 18 | logger.log( 19 | chalk.dim( 20 | `[${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}] Rebuilding due to changes in ${file}` 21 | ) 22 | ) 23 | }) 24 | 25 | compiler.hooks.done.tapPromise('print-status', async stats => { 26 | if (this.opts.clearConsole !== false && process.env.NODE_ENV !== 'test') { 27 | require('@poi/dev-utils/clearConsole')() 28 | } 29 | if (stats.hasErrors() || stats.hasWarnings()) { 30 | if (stats.hasErrors()) { 31 | process.exitCode = 1 32 | } 33 | 34 | // Print prettified errors and warnings 35 | const messages = formatWebpackMessages(stats.toJson()) 36 | if (messages) { 37 | const { errors, warnings } = messages 38 | for (const error of errors) { 39 | console.error(error) 40 | } 41 | for (const warning of warnings) { 42 | console.error(warning) 43 | } 44 | } 45 | // Print full stats in debug mode 46 | logger.debug(() => 47 | stats.toString({ 48 | colors: true 49 | }) 50 | ) 51 | } else { 52 | if (this.opts.printSucessMessage) { 53 | logger.done( 54 | `Build completed in ${prettyTime(stats.endTime - stats.startTime)}` 55 | ) 56 | } 57 | // Print file stats 58 | if ( 59 | (this.opts.printFileStats || logger.options.debug) && 60 | !process.env.CI && 61 | process.stdout.isTTY 62 | ) { 63 | logger.log() 64 | const assets = await Promise.all( 65 | stats.toJson().assets.map(async asset => { 66 | asset.gzipped = await gzipSize( 67 | stats.compilation.assets[asset.name].source() 68 | ) 69 | return asset 70 | }) 71 | ) 72 | const data = assets.map(asset => { 73 | const filename = path.relative( 74 | process.cwd(), 75 | path.join(compiler.options.output.path, asset.name) 76 | ) 77 | return [ 78 | path.join( 79 | path.dirname(filename), 80 | chalk.bold(path.basename(filename)) 81 | ), 82 | chalk.green(prettyBytes(asset.size)), 83 | chalk.green(prettyBytes(asset.gzipped)) 84 | ] 85 | }) 86 | data.unshift([ 87 | chalk.bold('file'), 88 | chalk.bold('size'), 89 | chalk.bold('gzipped') 90 | ]) 91 | data.push([ 92 | '(total)', 93 | chalk.green( 94 | prettyBytes( 95 | assets.reduce((result, asset) => result + asset.size, 0) 96 | ) 97 | ), 98 | chalk.green( 99 | prettyBytes( 100 | assets.reduce((result, asset) => result + asset.gzipped, 0) 101 | ) 102 | ) 103 | ]) 104 | logger.log( 105 | textTable(data, { 106 | stringLength: require('string-width') 107 | }) 108 | ) 109 | } 110 | } 111 | }) 112 | } 113 | } 114 | 115 | module.exports = PrintStatusPlugin 116 | -------------------------------------------------------------------------------- /core/poi/lib/webpack/babel-loader.js: -------------------------------------------------------------------------------- 1 | const babelLoader = require('babel-loader') 2 | const logger = require('@poi/logger') 3 | const spinner = require('../utils/spinner') 4 | 5 | const macroCheck = new RegExp('[./]macro') 6 | 7 | module.exports = babelLoader.custom(babel => { 8 | const configs = new Set() 9 | const presetItem = babel.createConfigItem(require('../babel/preset'), { 10 | type: 'preset' 11 | }) 12 | 13 | return { 14 | customOptions(opts) { 15 | const custom = opts.customLoaderOptions 16 | delete opts.customLoaderOptions 17 | 18 | return { loader: opts, custom } 19 | }, 20 | config(cfg, { source }) { 21 | const options = Object.assign({}, cfg.options, { 22 | caller: Object.assign({}, cfg.options.caller, { 23 | // for babel-plugin-macros it should never be cached 24 | poiInvalidationToken: macroCheck.test(source) 25 | ? require('crypto') 26 | .randomBytes(32) 27 | .toString('hex') 28 | : '' 29 | }) 30 | }) 31 | 32 | if (cfg.hasFilesystemConfig()) { 33 | for (const file of [cfg.babelrc, cfg.config]) { 34 | if (file && !configs.has(file)) { 35 | configs.add(file) 36 | spinner.stop() 37 | logger.debug(`Using external babel config file: ${file}`) 38 | } 39 | } 40 | } else { 41 | // Add our default preset if the no "babelrc" found. 42 | options.presets = [...options.presets, presetItem] 43 | } 44 | 45 | return options 46 | } 47 | } 48 | }) 49 | -------------------------------------------------------------------------------- /core/poi/lib/webpack/default-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= html.title %> 8 | 9 | <% if (pkg.description) { %> 10 | 11 | <% } %> 12 | 13 | 14 | 15 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /core/poi/lib/webpack/eval-loader.js: -------------------------------------------------------------------------------- 1 | const NativeModule = require('module') 2 | 3 | module.exports = async function(source, map) { 4 | this.cacheable() 5 | const done = this.async() 6 | 7 | const exec = (code, filename) => { 8 | delete require.cache[filename] 9 | const module = new NativeModule(filename, this) 10 | module.paths = NativeModule._nodeModulePaths(this.context) 11 | module.filename = filename 12 | module._compile(transpileEsModules(code, filename), filename) 13 | return module.exports.default || module.exports 14 | } 15 | 16 | try { 17 | const exported = exec(source, this.resourcePath) 18 | const result = await exported.call(this) 19 | done(null, `${JSON.stringify(result)}`, map) 20 | } catch (error) { 21 | done(error) 22 | } 23 | } 24 | 25 | function transpileEsModules(code, filename) { 26 | const RE = /\b(import|export)\b/ 27 | if (!RE.test(code)) { 28 | return code 29 | } 30 | // Use babel-preset-env to transpile potentional `import/export` statements 31 | return require('@babel/core').transform(code, { 32 | filename, 33 | babelrc: false, 34 | configFile: false, 35 | presets: [ 36 | [ 37 | require.resolve('@babel/preset-env'), 38 | { 39 | targets: { 40 | node: 'current' 41 | } 42 | } 43 | ] 44 | ] 45 | }).code 46 | } 47 | -------------------------------------------------------------------------------- /core/poi/lib/webpack/reason-loader.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | const { watch } = this.query || {} 3 | const outFile = this.resourcePath.replace(/\.(re|ml)$/, '.bs.js') 4 | const fs = this.fs || require('fs') 5 | try { 6 | fs.statSync(outFile) 7 | return `export * from ${JSON.stringify(outFile)}` 8 | } catch (_) { 9 | throw new Error( 10 | `Cannot find ${outFile}\nYou must run \`bsb -make-world${ 11 | watch ? ' -w' : '' 12 | }\` first.` 13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/poi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poi", 3 | "version": "12.10.3", 4 | "main": "lib/index.js", 5 | "bin": "bin/cli.js", 6 | "description": "A zero-config bundler for JavaScript applications.", 7 | "scripts": { 8 | "test": "jest" 9 | }, 10 | "files": [ 11 | "lib", 12 | "bin", 13 | "babel.js", 14 | "webpack.config.js", 15 | "!**/__test__/**" 16 | ], 17 | "license": "MIT", 18 | "dependencies": { 19 | "@babel/core": "^7.1.6", 20 | "@babel/plugin-proposal-class-properties": "^7.1.0", 21 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 22 | "@babel/plugin-proposal-optional-chaining": "^7.9.0", 23 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 24 | "@babel/plugin-syntax-jsx": "^7.0.0", 25 | "@babel/plugin-transform-flow-strip-types": "^7.1.6", 26 | "@babel/plugin-transform-runtime": "^7.1.0", 27 | "@babel/preset-env": "^7.1.6", 28 | "@babel/preset-react": "^7.0.0", 29 | "@babel/preset-typescript": "^7.1.0", 30 | "@babel/runtime": "^7.1.5", 31 | "@intervolga/optimize-cssnano-plugin": "^1.0.6", 32 | "@pmmmwh/react-refresh-webpack-plugin": "^0.4.1", 33 | "@poi/dev-utils": "^12.1.6", 34 | "@poi/logger": "^12.0.0", 35 | "@poi/plugin-html-entry": "^0.2.3", 36 | "@poi/pnp-webpack-plugin": "^0.0.2", 37 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 38 | "babel-loader": "^8.0.4", 39 | "babel-plugin-assets-named-imports": "^0.2.1", 40 | "babel-plugin-macros": "^2.4.2", 41 | "babel-plugin-transform-vue-jsx": "^4.0.0", 42 | "cac": "^6.3.12", 43 | "cache-loader": "^4.1.0", 44 | "case-sensitive-paths-webpack-plugin": "^2.1.2", 45 | "chalk": "^2.4.1", 46 | "copy-webpack-plugin": "^5.1.1", 47 | "css-loader": "^3.0.0", 48 | "cssnano": "^4.1.7", 49 | "dotenv": "^8.1.0", 50 | "dotenv-expand": "^4.2.0", 51 | "extract-css-chunks-webpack-plugin": "^4.7.4", 52 | "file-loader": "^2.0.0", 53 | "fs-extra": "^9.0.0", 54 | "get-port": "^5.0.0", 55 | "gzip-size": "^5.0.0", 56 | "html-webpack-plugin": "^4.0.0-beta.4", 57 | "joycon": "^2.2.1", 58 | "launch-editor-middleware": "^2.2.1", 59 | "lodash.merge": "^4.6.1", 60 | "ora": "^3.0.0", 61 | "postcss-loader": "^3.0.0", 62 | "pretty-ms": "^4.0.0", 63 | "react-refresh": "^0.8.3", 64 | "resolve-from": "^5.0.0", 65 | "string-width": "^4.1.0", 66 | "superstruct": "^0.6.0", 67 | "terser-webpack-plugin": "^2.1.2", 68 | "text-table": "^0.2.0", 69 | "thread-loader": "^1.2.0", 70 | "url-loader": "^4.1.0", 71 | "v8-compile-cache": "^2.0.2", 72 | "vue-loader": "^15.4.2", 73 | "vue-style-loader": "^4.1.2", 74 | "webpack": "^4.26.0", 75 | "webpack-chain": "^6.4.0", 76 | "webpack-dev-server": "^3.11.0", 77 | "webpack-merge": "^4.1.4" 78 | }, 79 | "xo": false, 80 | "devDependencies": { 81 | "@poi/test-utils": "^12.0.2", 82 | "vue-template-compiler": "^2.5.21" 83 | }, 84 | "keywords": [ 85 | "poi", 86 | "webpack", 87 | "zero-config", 88 | "bundler", 89 | "vue-cli", 90 | "parcel", 91 | "create-react-app", 92 | "babel" 93 | ] 94 | } 95 | -------------------------------------------------------------------------------- /core/poi/webpack.config.js: -------------------------------------------------------------------------------- 1 | const Poi = require('.') 2 | 3 | const poi = new Poi() 4 | 5 | module.exports = poi.createWebpackChain().toConfig() 6 | -------------------------------------------------------------------------------- /core/test-utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [12.0.2](https://github.com/egoist/poi/compare/@poi/test-utils@12.0.1...@poi/test-utils@12.0.2) (2020-04-30) 7 | 8 | **Note:** Version bump only for package @poi/test-utils 9 | 10 | 11 | 12 | 13 | 14 | ## [12.0.1](https://github.com/egoist/poi/compare/@poi/test-utils@12.0.0...@poi/test-utils@12.0.1) (2019-07-27) 15 | 16 | **Note:** Version bump only for package @poi/test-utils 17 | -------------------------------------------------------------------------------- /core/test-utils/createProject.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const glob = require('fast-glob') 3 | const execa = require('execa') 4 | const fs = require('fs-extra') 5 | 6 | module.exports = async ({ name = Date.now() } = {}) => { 7 | const cwd = path.join(__dirname, `.test-projects/poi-${name}`) 8 | /** @type {string[]} */ 9 | let files 10 | 11 | await fs.remove(cwd) 12 | 13 | const run = async cmd => { 14 | const [name, ...args] = cmd.split(' ') 15 | await execa(name, args, { cwd }) 16 | files = await glob(['**/*', '!**/node_modules**'], { cwd }) 17 | } 18 | 19 | return { 20 | get files() { 21 | return files.sort() 22 | }, 23 | run, 24 | has(file) { 25 | return files && files.includes(file) 26 | }, 27 | async write(file, content) { 28 | await fs.outputFile(path.join(cwd, file), content, 'utf8') 29 | }, 30 | require(file) { 31 | return require(path.join(cwd, file)) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/test-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/test-utils", 3 | "version": "12.0.2", 4 | "files": [ 5 | "*.js" 6 | ], 7 | "publishConfig": { 8 | "access": "public" 9 | }, 10 | "xo": false, 11 | "dependencies": { 12 | "execa": "^1.0.0", 13 | "fast-glob": "^3.0.4", 14 | "fs-extra": "^9.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /create-poi-app/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [12.2.2](https://github.com/egoist/poi/compare/create-poi-app@12.2.1...create-poi-app@12.2.2) (2020-08-19) 7 | 8 | **Note:** Version bump only for package create-poi-app 9 | 10 | ## [12.2.1](https://github.com/egoist/poi/compare/create-poi-app@12.2.0...create-poi-app@12.2.1) (2020-04-30) 11 | 12 | **Note:** Version bump only for package create-poi-app 13 | 14 | # [12.2.0](https://github.com/egoist/poi/compare/create-poi-app@12.1.2...create-poi-app@12.2.0) (2019-07-03) 15 | 16 | ### Features 17 | 18 | - **create-poi-app:** add update notifier in pwa ([#580](https://github.com/egoist/poi/issues/580)) ([5b4bbaf](https://github.com/egoist/poi/commit/5b4bbaf)) 19 | 20 | ## [12.1.2](https://github.com/egoist/poi/compare/create-poi-app@12.1.1...create-poi-app@12.1.2) (2019-01-09) 21 | 22 | ### Bug Fixes 23 | 24 | - properly add pnp plugins ([fdcd9e7](https://github.com/egoist/poi/commit/fdcd9e7)) 25 | 26 | ## [12.1.1](https://github.com/egoist/poi/compare/create-poi-app@12.1.0...create-poi-app@12.1.1) (2019-01-09) 27 | 28 | ### Bug Fixes 29 | 30 | - support yarn pnp ([ca61aaa](https://github.com/egoist/poi/commit/ca61aaa)) 31 | 32 | # [12.1.0](https://github.com/egoist/poi/compare/create-poi-app@12.0.3...create-poi-app@12.1.0) (2019-01-09) 33 | 34 | ### Features 35 | 36 | - use plugin-karma 13 in create-poi-app ([2b2ae26](https://github.com/egoist/poi/commit/2b2ae26)) 37 | 38 | ## [12.0.3](https://github.com/egoist/poi/compare/create-poi-app@12.0.2...create-poi-app@12.0.3) (2018-12-25) 39 | 40 | ### Features 41 | 42 | - add a hook to allow modifing devServer config ([df939e6](https://github.com/egoist/poi/commit/df939e6)) 43 | -------------------------------------------------------------------------------- /create-poi-app/README.md: -------------------------------------------------------------------------------- 1 | # Create Poi App 2 | 3 | ```bash 4 | npm i -g create-poi-app 5 | 6 | cpa my-app 7 | ``` 8 | -------------------------------------------------------------------------------- /create-poi-app/bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const path = require('path') 3 | const cli = require('cac')() 4 | 5 | cli 6 | .command('', 'Generate a new project to target folder') 7 | .option( 8 | '--npm-client ', 9 | `Choose an npm client for installing packages ('yarn' | 'npm' | 'pnpm')` 10 | ) 11 | .action(async (targetFolder, { npmClient }) => { 12 | const sao = require('sao') 13 | 14 | const app = sao({ 15 | generator: path.join(__dirname, '../generator'), 16 | outDir: targetFolder, 17 | npmClient 18 | }) 19 | 20 | await app.run().catch(sao.handleError) 21 | }) 22 | 23 | cli.help() 24 | cli.version(require('../package').version) 25 | 26 | cli.parse() 27 | -------------------------------------------------------------------------------- /create-poi-app/generator/__test__/index.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const sao = require('sao') 3 | 4 | const generator = path.join(__dirname, '..') 5 | 6 | test('defaults', async () => { 7 | const stream = await sao.mock( 8 | { generator }, 9 | { 10 | features: ['linter'], 11 | linterConfig: 'xo' 12 | } 13 | ) 14 | expect(stream.fileList).toContain('.eslintrc.js') 15 | const pkg = JSON.parse(await stream.readFile('package.json')) 16 | const deps = [...Object.keys(pkg.devDependencies)] 17 | expect(deps).toContain('eslint') 18 | expect(deps).toContain('eslint-config-xo') 19 | expect(deps).toContain('@poi/plugin-eslint') 20 | expect(pkg.scripts.lint).toBe('eslint .') 21 | }) 22 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/js/src/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | import './assets/css/style.css'; 3 | 4 | const title = document.createElement('h1'); 5 | title.textContent = 'Hello Poi!'; 6 | title.className = 'title'; 7 | 8 | const tip = document.createElement('div'); 9 | tip.textContent = 'Edit src/index.js and save to reload.'; 10 | tip.className = 'tip'; 11 | 12 | const app = document.getElementById('app'); 13 | 14 | if (app) { 15 | app.appendChild(title); 16 | app.appendChild(tip); 17 | } 18 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/js/src/index.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env jasmine */ 2 | describe('main', () => { 3 | it('works', () => { 4 | expect(1).toBe(1); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/linter-tslint/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "node_modules/**" 9 | ] 10 | }, 11 | "rules": { 12 | "quotemark": [true, "single"], 13 | "indent": [true, "spaces", 2], 14 | "interface-name": false, 15 | "ordered-imports": false, 16 | "object-literal-sort-keys": false, 17 | "no-consecutive-blank-lines": false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/linter-xo/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'xo' 4 | ], 5 | rules: { 6 | indent: ['error', 2] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/README.md: -------------------------------------------------------------------------------- 1 | # <%= context.outFolder %> 2 | 3 | > Created by [create-poi-app](https://poi.js.org). 4 | 5 | ## Project Scripts 6 | 7 | ### `npm run build` 8 | 9 | Build app for production to `./dist` folder. 10 | 11 | ### `npm run dev` 12 | 13 | Start a dev server to preview your app. 14 | 15 | <% if (unit) { %> 16 | 17 | ### `npm run test:unit` 18 | 19 | Run unit tests. 20 | <% } %> 21 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/_gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/poi.config.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/poi/25f782797c4bf4e85ab3a23c0a6a040f7843c5db/create-poi-app/generator/templates/main/poi.config.js -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/poi/25f782797c4bf4e85ab3a23c0a6a040f7843c5db/create-poi-app/generator/templates/main/public/favicon.ico -------------------------------------------------------------------------------- /create-poi-app/generator/templates/main/src/assets/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: #333; 4 | color: #74d7fd; 5 | text-align: center; 6 | } 7 | 8 | .title { 9 | margin-top: 300px; 10 | font-size: 4rem; 11 | } 12 | 13 | .tip { 14 | font-size: 1.4rem; 15 | } 16 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/pwa/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/poi/25f782797c4bf4e85ab3a23c0a6a040f7843c5db/create-poi-app/generator/templates/pwa/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /create-poi-app/generator/templates/pwa/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/poi/25f782797c4bf4e85ab3a23c0a6a040f7843c5db/create-poi-app/generator/templates/pwa/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /create-poi-app/generator/templates/pwa/public/img/icons/safari-mask-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/pwa/public/manifest.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/pwa/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 2 | const { Workbox } = require('workbox-window') 3 | 4 | const workbox = new Workbox(`${process.env.PUBLIC_URL}service-worker.js`) 5 | 6 | const addNotifier = () => { 7 | const { createSnackbar } = require('@egoist/snackbar') 8 | require('@egoist/snackbar/dist/snackbar.css') 9 | 10 | const pwaFirstTimeInstallMessage = 'Ready for offline use' 11 | const pwaUpdateReadyMessage = 'A new version of this app is available' 12 | const pwaUpdateButtonMessage = 'UPDATE' 13 | const pwaDismissMessage = 'DISMISS' 14 | 15 | const showUpdateNotifier = () => { 16 | createSnackbar(pwaUpdateReadyMessage, { 17 | position: 'right', 18 | timeout: 20000, 19 | actions: [ 20 | { 21 | text: pwaUpdateButtonMessage, 22 | style: { 23 | color: 'pink' 24 | }, 25 | callback(button) { 26 | button.innerHTML = `` 27 | button.disabled = true 28 | 29 | workbox.addEventListener('controlling', () => { 30 | window.location.reload() 31 | }) 32 | 33 | workbox.messageSW({ type: 'SKIP_WAITING' }) 34 | } 35 | } 36 | ] 37 | }) 38 | } 39 | 40 | workbox.addEventListener('installed', event => { 41 | if (!event.isUpdate) { 42 | createSnackbar(pwaFirstTimeInstallMessage, { 43 | position: 'right', 44 | timeout: 5000, 45 | actions: [ 46 | { 47 | text: pwaDismissMessage 48 | } 49 | ] 50 | }) 51 | } 52 | }) 53 | 54 | workbox.addEventListener('waiting', () => { 55 | showUpdateNotifier() 56 | }) 57 | } 58 | 59 | addNotifier() 60 | 61 | workbox.register() 62 | } 63 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/ts/src/index.test.ts: -------------------------------------------------------------------------------- 1 | describe('main', () => { 2 | it('works', () => { 3 | expect(1).toBe(1); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/ts/src/index.ts: -------------------------------------------------------------------------------- 1 | import './assets/css/style.css'; 2 | 3 | const title = document.createElement('h1'); 4 | title.textContent = 'Hello Poi!'; 5 | title.className = 'title'; 6 | 7 | const tip = document.createElement('div'); 8 | tip.textContent = 'Edit src/index.ts and save to reload.'; 9 | tip.className = 'tip'; 10 | 11 | const app = document.getElementById('app'); 12 | 13 | if (app) { 14 | app.appendChild(title); 15 | app.appendChild(tip); 16 | } 17 | -------------------------------------------------------------------------------- /create-poi-app/generator/templates/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "es5", 5 | "strict": true, 6 | "moduleResolution": "node" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /create-poi-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-poi-app", 3 | "version": "12.2.2", 4 | "license": "MIT", 5 | "files": [ 6 | "bin", 7 | "generator", 8 | "!**/__test__/**" 9 | ], 10 | "scripts": { 11 | "test": "jest" 12 | }, 13 | "bin": { 14 | "cpa": "bin/cli.js", 15 | "create-poi-app": "bin/cli.js" 16 | }, 17 | "dependencies": { 18 | "cac": "^6.3.12", 19 | "sao": "^1.6.1", 20 | "stringify-object": "^3.3.0" 21 | }, 22 | "xo": false, 23 | "jest": { 24 | "testPathIgnorePatterns": [ 25 | "/templates/" 26 | ], 27 | "testEnvironment": "node" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "useWorkspaces": true, 4 | "independent": true, 5 | "version": "independent", 6 | "ignoreChanges": ["**/__fixtures__/**", "**/__tests__/**", "**/*.md"], 7 | "command": { 8 | "publish": { 9 | "message": "chore(release): publish" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /other-packages/babel-plugin-assets-named-imports/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.2.1](https://github.com/egoist/poi/compare/babel-plugin-assets-named-imports@0.2.0...babel-plugin-assets-named-imports@0.2.1) (2020-04-30) 7 | 8 | **Note:** Version bump only for package babel-plugin-assets-named-imports 9 | 10 | 11 | 12 | 13 | 14 | # 0.2.0 (2018-12-18) 15 | 16 | ### Features 17 | 18 | - named imports for assets ([#505](https://github.com/egoist/poi/issues/505)) ([32f153a](https://github.com/egoist/poi/commit/32f153a)) 19 | -------------------------------------------------------------------------------- /other-packages/babel-plugin-assets-named-imports/__test__/index.test.js: -------------------------------------------------------------------------------- 1 | const babel = require('@babel/core') 2 | const namedAssetImport = require('..') 3 | 4 | const pluginTester = ({ plugin, pluginOptions, tests }) => { 5 | for (const testTitle of Object.keys(tests)) { 6 | test(testTitle, () => { 7 | const { code, output } = tests[testTitle] 8 | expect( 9 | babel.transform(code, { 10 | plugins: [[plugin, pluginOptions]], 11 | babelrc: false, 12 | configFile: false 13 | }).code 14 | ).toBe(output) 15 | }) 16 | } 17 | } 18 | 19 | pluginTester({ 20 | plugin: namedAssetImport, 21 | pluginOptions: { 22 | loaderMap: { 23 | svg: { 24 | ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', 25 | default: 'default![path]' 26 | } 27 | } 28 | }, 29 | pluginName: 'named-asset-import', 30 | tests: { 31 | defaultImport: { 32 | code: 'import logo from "logo";', 33 | output: 'import logo from "logo";' 34 | }, 35 | namedImport: { 36 | code: 'import { logo } from "logo";', 37 | output: 'import { logo } from "logo";' 38 | }, 39 | namedImportRenamed: { 40 | code: 'import { Url as logo1 } from "logo";', 41 | output: 'import { Url as logo1 } from "logo";' 42 | }, 43 | svgDefaultImport: { 44 | code: 'import logo from "logo.svg";', 45 | output: 'import logo from "default!logo.svg";' 46 | }, 47 | svgNamedImport: { 48 | code: 'import { logo } from "logo.svg";', 49 | output: 'import { logo } from "logo.svg";' 50 | }, 51 | svgReactComponentNamedImport: { 52 | code: 'import { ReactComponent as logo } from "logo.svg";', 53 | output: 'import logo from "@svgr/webpack?-prettier,-svgo!logo.svg";' 54 | }, 55 | svgMultipleImport: { 56 | code: 57 | 'import logo, { logoUrl , ReactComponent as Logo } from "logo.svg";', 58 | output: 59 | 'import logo from "default!logo.svg";\n' + 60 | 'import { logoUrl } from "logo.svg";\n' + 61 | 'import Logo from "@svgr/webpack?-prettier,-svgo!logo.svg";' 62 | }, 63 | defaultExport: { 64 | code: 'export default logo;', 65 | output: 'export default logo;' 66 | }, 67 | constExport: { 68 | code: 'export const token = "token";', 69 | output: 'export const token = "token";' 70 | }, 71 | classExport: { 72 | code: 'export class Logo {}', 73 | output: 'export class Logo {}' 74 | }, 75 | namedExport: { 76 | code: 'export { logo } from "logo";', 77 | output: 'export { logo } from "logo";' 78 | }, 79 | namedExportRenamed: { 80 | code: 'export { Url as logo } from "logo";', 81 | output: 'export { Url as logo } from "logo";' 82 | }, 83 | allExport: { 84 | code: 'export * from "logo";', 85 | output: 'export * from "logo";' 86 | }, 87 | svgNamedExport: { 88 | code: 'export { logo } from "logo.svg";', 89 | output: 'export { logo } from "logo.svg";' 90 | }, 91 | svgAllExport: { 92 | code: 'export * from "logo.svg";', 93 | output: 'export * from "logo.svg";' 94 | }, 95 | svgReactComponentNamedExport: { 96 | code: 'export { ReactComponent as Logo } from "logo.svg";', 97 | output: 98 | 'export { default as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";' 99 | }, 100 | svgReactComponentExport: { 101 | code: 'export { ReactComponent } from "logo.svg";', 102 | output: 103 | 'export { default as ReactComponent } from "@svgr/webpack?-prettier,-svgo!logo.svg";' 104 | }, 105 | svgMultipleExport: { 106 | code: 'export { logoUrl , ReactComponent as Logo } from "logo.svg";', 107 | output: 108 | 'export { logoUrl } from "logo.svg";\n' + 109 | 'export { default as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";' 110 | } 111 | } 112 | }) 113 | -------------------------------------------------------------------------------- /other-packages/babel-plugin-assets-named-imports/index.js: -------------------------------------------------------------------------------- 1 | const { extname } = require('path') 2 | 3 | /** 4 | * @param {Object} babel 5 | * @param {import('@babel/types')} babel.types 6 | */ 7 | function namedAssetImportPlugin({ types: t }) { 8 | const visited = new WeakSet() 9 | 10 | function generateNewSourcePath(loaderMap, moduleName, sourcePath) { 11 | const ext = extname(sourcePath).substr(1) 12 | const extMap = loaderMap[ext] 13 | return extMap[moduleName] 14 | ? extMap[moduleName].replace(/\[path\]/, sourcePath) 15 | : sourcePath 16 | } 17 | 18 | function replaceMatchingSpecifiers(path, loaderMap, callback) { 19 | const sourcePath = path.node.source.value 20 | const ext = extname(sourcePath).substr(1) 21 | 22 | if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) { 23 | return 24 | } 25 | 26 | if (loaderMap[ext]) { 27 | path.replaceWithMultiple( 28 | path.node.specifiers.map(specifier => { 29 | const newSpecifier = callback(specifier, sourcePath) 30 | visited.add(newSpecifier) 31 | 32 | return newSpecifier 33 | }) 34 | ) 35 | } 36 | } 37 | 38 | return { 39 | visitor: { 40 | ExportNamedDeclaration( 41 | path, 42 | { 43 | opts: { loaderMap } 44 | } 45 | ) { 46 | if (!path.node.source) { 47 | return 48 | } 49 | 50 | replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => { 51 | if (t.isExportDefaultSpecifier(specifier)) { 52 | return t.exportDeclaration( 53 | [t.exportDefaultSpecifier(t.identifier(specifier.local.name))], 54 | t.stringLiteral(sourcePath) 55 | ) 56 | } 57 | 58 | const newSourcePath = generateNewSourcePath( 59 | loaderMap, 60 | specifier.local.name, 61 | sourcePath 62 | ) 63 | 64 | if (newSourcePath === sourcePath) { 65 | return t.exportNamedDeclaration( 66 | null, 67 | [specifier], 68 | t.stringLiteral(sourcePath) 69 | ) 70 | } 71 | 72 | return t.exportNamedDeclaration( 73 | null, 74 | [ 75 | t.exportSpecifier( 76 | t.identifier('default'), 77 | t.identifier(specifier.exported.name) 78 | ) 79 | ], 80 | t.stringLiteral(newSourcePath) 81 | ) 82 | }) 83 | }, 84 | ImportDeclaration( 85 | path, 86 | { 87 | opts: { loaderMap } 88 | } 89 | ) { 90 | replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => { 91 | const isDefaultImport = t.isImportDefaultSpecifier(specifier) 92 | const newSoucePath = generateNewSourcePath( 93 | loaderMap, 94 | isDefaultImport ? 'default' : specifier.imported.name, 95 | sourcePath 96 | ) 97 | 98 | if (newSoucePath === sourcePath) { 99 | return t.importDeclaration([specifier], t.stringLiteral(sourcePath)) 100 | } 101 | 102 | return t.importDeclaration( 103 | [t.importDefaultSpecifier(t.identifier(specifier.local.name))], 104 | t.stringLiteral(newSoucePath) 105 | ) 106 | }) 107 | } 108 | } 109 | } 110 | } 111 | 112 | module.exports = namedAssetImportPlugin 113 | -------------------------------------------------------------------------------- /other-packages/babel-plugin-assets-named-imports/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-assets-named-imports", 3 | "publishConfig": { 4 | "access": "public" 5 | }, 6 | "scripts": { 7 | "test": "jest --env node" 8 | }, 9 | "version": "0.2.1", 10 | "main": "index.js", 11 | "files": [ 12 | "index.js" 13 | ], 14 | "license": "MIT", 15 | "xo": false, 16 | "devDependencies": { 17 | "@babel/core": "^7.2.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /other-packages/pnp-webpack-plugin/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.2](https://github.com/egoist/poi/compare/@poi/pnp-webpack-plugin@0.0.1...@poi/pnp-webpack-plugin@0.0.2) (2019-01-11) 7 | 8 | ### Bug Fixes 9 | 10 | - remove pnpapi ([ff7f198](https://github.com/egoist/poi/commit/ff7f198)) 11 | 12 | ## 0.0.1 (2019-01-09) 13 | 14 | ### Bug Fixes 15 | 16 | - support yarn pnp ([ca61aaa](https://github.com/egoist/poi/commit/ca61aaa)) 17 | -------------------------------------------------------------------------------- /other-packages/pnp-webpack-plugin/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Forked from https://github.com/arcanis/pnp-webpack-plugin/blob/09cbab561/index.js 3 | // Without ts-pnp 4 | 5 | const path = require(`path`); 6 | 7 | let pnp; 8 | 9 | try { 10 | pnp = require(`pnpapi`); 11 | } catch (error) { 12 | // not in PnP; not a problem 13 | } 14 | 15 | function nothing() { 16 | // ¯\_(ツ)_/¯ 17 | } 18 | 19 | function getModuleLocator(module) { 20 | const moduleLocation = module.filename; 21 | 22 | if (!moduleLocation) 23 | throw new Error(`The specified module doesn't seem to exist on the filesystem`); 24 | 25 | const moduleLocator = pnp.findPackageLocator(moduleLocation); 26 | 27 | if (!moduleLocator) 28 | throw new Error(`the specified module doesn't seem to be part of the dependency tree`); 29 | 30 | return moduleLocator; 31 | } 32 | 33 | function getSourceLocation(sourceLocator) { 34 | if (!sourceLocator) 35 | return null; 36 | 37 | const sourceInformation = pnp.getPackageInformation(sourceLocator); 38 | 39 | if (!sourceInformation) 40 | throw new Error(`Couldn't find the package to use as resolution source`); 41 | 42 | if (!sourceInformation.packageLocation) 43 | throw new Error(`The package to use as resolution source seem to not have been installed - maybe it's a devDependency not installed in prod?`); 44 | 45 | return sourceInformation.packageLocation.replace(/\/?$/, `/`); 46 | } 47 | 48 | function makeResolver(sourceLocator) { 49 | const sourceLocation = getSourceLocation(sourceLocator); 50 | 51 | return resolver => { 52 | const MAYBE_BUILTIN = /^[^\/]$/; 53 | 54 | const resolvedHook = resolver.ensureHook(`resolve`); 55 | 56 | // Prevents the SymlinkPlugin from kicking in. We need the symlinks to be preserved because that's how we deal with peer dependencies ambiguities. 57 | resolver.getHook(`file`).intercept({ 58 | register: tapInfo => { 59 | return tapInfo.name !== `SymlinkPlugin` ? tapInfo : Object.assign({}, tapInfo, {fn: (request, resolveContext, callback) => { 60 | callback(); 61 | }}); 62 | } 63 | }); 64 | 65 | // Register a plugin that will resolve bare imports into the package location on the filesystem before leaving the rest of the resolution to Webpack 66 | resolver.getHook(`before-module`).tapAsync(`PnpResolver`, (requestContext, resolveContext, callback) => { 67 | let request = requestContext.request; 68 | let issuer = sourceLocation || requestContext.context.issuer; 69 | 70 | // When using require.context, issuer seems to be false (cf https://github.com/webpack/webpack-dev-server/blob/d0725c98fb752d8c0b1e8c9067e526e22b5f5134/client-src/default/index.js#L94) 71 | if (!issuer) { 72 | issuer = `${requestContext.path}/`; 73 | // We only support issuer when they're absolute paths. I'm not sure the opposite can ever happen, but better check here. 74 | } else if (!path.isAbsolute(issuer)) { 75 | throw new Error(`Cannot successfully resolve this dependency - issuer not supported (${issuer})`); 76 | } 77 | 78 | let resolution; 79 | 80 | try { 81 | resolution = pnp.resolveToUnqualified(request, issuer, {considerBuiltins: false}); 82 | } catch (error) { 83 | return callback(error); 84 | } 85 | 86 | resolver.doResolve( 87 | resolvedHook, 88 | Object.assign({}, requestContext, { 89 | request: resolution, 90 | }), 91 | null, 92 | resolveContext, 93 | callback 94 | ); 95 | }); 96 | }; 97 | } 98 | 99 | module.exports = pnp ? { 100 | apply: makeResolver(null), 101 | } : { 102 | apply: nothing, 103 | }; 104 | 105 | module.exports.moduleLoader = module => pnp ? { 106 | apply: makeResolver(getModuleLocator(module)), 107 | } : { 108 | apply: nothing, 109 | }; 110 | 111 | module.exports.topLevelLoader = pnp ? { 112 | apply: makeResolver(pnp.topLevel), 113 | } : { 114 | apply: nothing, 115 | }; 116 | -------------------------------------------------------------------------------- /other-packages/pnp-webpack-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/pnp-webpack-plugin", 3 | "version": "0.0.2", 4 | "files": [ 5 | "index.js" 6 | ], 7 | "publishConfig": { 8 | "access": "public" 9 | }, 10 | "main": "index.js", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /other-packages/pwa-html-webpack-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pwa-html-webpack-plugin", 3 | "publishConfig": { 4 | "access": "public" 5 | }, 6 | "version": "12.0.0", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "license": "MIT", 12 | "xo": false 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "poi", 4 | "scripts": { 5 | "lint": "xo", 6 | "test": "sh tasks/test.sh", 7 | "commit": "git-cz", 8 | "release": "lerna version --conventional-commits" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:egoist/poi.git" 13 | }, 14 | "workspaces": [ 15 | "core/*", 16 | "plugins/*", 17 | "other-packages/*", 18 | "create-poi-app" 19 | ], 20 | "devDependencies": { 21 | "commitizen": "^3.0.5", 22 | "cz-conventional-changelog": "^2.1.0", 23 | "eslint-config-prettier": "^6.0.0", 24 | "eslint-config-rem": "^4.0.0", 25 | "eslint-plugin-prettier": "^3.0.0", 26 | "husky": "^4.2.5", 27 | "jest": "^25.5.2", 28 | "lerna": "^3.22.1", 29 | "lint-staged": "^8.1.0", 30 | "xo": "^0.23.0" 31 | }, 32 | "xo": { 33 | "extends": [ 34 | "rem", 35 | "plugin:prettier/recommended" 36 | ], 37 | "rules": { 38 | "unicorn/filename-case": "off", 39 | "no-await-in-loop": "off", 40 | "unicorn/no-abusive-eslint-disable": "off", 41 | "no-multi-assign": "off", 42 | "camelcase": "off" 43 | }, 44 | "envs": [ 45 | "jest" 46 | ], 47 | "ignores": [ 48 | "create-poi-app/generator/templates/**", 49 | "test/kitchensink/**", 50 | "**/example/**" 51 | ] 52 | }, 53 | "husky": { 54 | "hooks": { 55 | "pre-commit": "lint-staged" 56 | } 57 | }, 58 | "lint-staged": { 59 | "linters": { 60 | "*.js": [ 61 | "xo --fix", 62 | "git add" 63 | ], 64 | "*.{md,json}": [ 65 | "prettier --write", 66 | "git add" 67 | ] 68 | }, 69 | "ignore": [ 70 | "create-poi-app/generator/templates/**", 71 | "test/kitchensink/**", 72 | "**/example/**" 73 | ] 74 | }, 75 | "config": { 76 | "commitizen": { 77 | "path": "cz-conventional-changelog" 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /plugins/astroturf/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.2.0](https://github.com/egoist/poi/compare/@poi/plugin-astroturf@0.1.1...@poi/plugin-astroturf@0.2.0) (2020-04-30) 7 | 8 | 9 | ### Features 10 | 11 | * CSS modules should export camelCased names ([#585](https://github.com/egoist/poi/issues/585)) ([5567a8c](https://github.com/egoist/poi/commit/5567a8c)) 12 | 13 | 14 | 15 | 16 | 17 | ## [0.1.1](https://github.com/egoist/poi/compare/@poi/plugin-astroturf@0.1.0...@poi/plugin-astroturf@0.1.1) (2019-07-27) 18 | 19 | **Note:** Version bump only for package @poi/plugin-astroturf 20 | 21 | # 0.1.0 (2019-04-03) 22 | 23 | ### Features 24 | 25 | - add plugin astroturf resolve [#548](https://github.com/egoist/poi/issues/548) ([#551](https://github.com/egoist/poi/issues/551)) ([d809c61](https://github.com/egoist/poi/commit/d809c61)) 26 | -------------------------------------------------------------------------------- /plugins/astroturf/README.md: -------------------------------------------------------------------------------- 1 | # @poi/plugin-astroturf 2 | 3 | Use [astroturf](https://github.com/4Catalyzer/astroturf) to write CSS in JS with zero-runtime. 4 | 5 | ## Install 6 | 7 | ```bash 8 | yarn add astroturf @poi/plugin-astroturf --dev 9 | ``` 10 | 11 | ## How to use 12 | 13 | In your `poi.config.js`: 14 | 15 | ```js 16 | module.exports = { 17 | plugins: [ 18 | { 19 | resolve: '@poi/plugin-astroturf', 20 | options: {} 21 | } 22 | ] 23 | } 24 | ``` 25 | 26 | Then write css-in-js: 27 | 28 | ```jsx 29 | import { css } from 'astroturf' 30 | 31 | const style = css` 32 | .title { 33 | font-size: 2em; 34 | } 35 | ` 36 | export const App = () => { 37 | return
Hello world
38 | } 39 | ``` 40 | 41 | Check out [astroturf](https://github.com/4Catalyzer/astroturf/) for more usages. 42 | 43 | ## Options 44 | 45 | - `loaderOptions`: `astroturf/loader` [options](https://github.com/4Catalyzer/astroturf/tree/1741c3e702049f6e75483cd000b439d42e57ef2d#options) 46 | - `loaderOptions.extension`: Default `.module.css`. You can also change it to `.scss` or `.module.scss` etc to use [CSS pre-processors](https://poi.js.org/guide/pre-processing-css.html), but make sure that it ends with `.module.xxx` if you want CSS modules support. 47 | 48 | ## License 49 | 50 | MIT. 51 | -------------------------------------------------------------------------------- /plugins/astroturf/index.js: -------------------------------------------------------------------------------- 1 | exports.name = 'astroturf' 2 | 3 | /** 4 | * The @poi/astroturf plugin options 5 | * @typedef {Object} AstroturfOptions 6 | * @property {Object} loaderOptions - The `astroturf/loader` options 7 | * See also {@link https://github.com/4Catalyzer/astroturf/tree/1741c3e702049f6e75483cd000b439d42e57ef2d#options} 8 | */ 9 | 10 | exports.apply = (api, options = {}) => { 11 | const loaderOptions = Object.assign( 12 | { 13 | extension: '.module.css' 14 | }, 15 | options.loaderOptions 16 | ) 17 | 18 | const loaderPath = api.localResolve('astroturf/loader') 19 | if (!loaderPath) { 20 | throw new api.PoiError( 21 | `Cannot find module "astroturf/loader" in your project, did you forget to install "astroturf"?` 22 | ) 23 | } 24 | 25 | api.hook('createWebpackChain', config => { 26 | const jsRule = config.module.rule('js') 27 | 28 | addAstroturfLoader(jsRule, loaderOptions, loaderPath) 29 | if (config.module.rules.get('ts')) { 30 | addAstroturfLoader(config.module.rule('ts'), loaderOptions, loaderPath) 31 | } 32 | }) 33 | } 34 | 35 | /** 36 | * @private 37 | * @param {import('webpack-chain').Rule} rule 38 | * @param {AstroturfOptions.loaderOptions} loaderOptions 39 | * @param {string} loaderPath 40 | */ 41 | function addAstroturfLoader(rule, loaderOptions, loaderPath) { 42 | rule 43 | .use('astroturf-loader') 44 | .loader(loaderPath) 45 | .options(loaderOptions) 46 | } 47 | -------------------------------------------------------------------------------- /plugins/astroturf/index.test.js: -------------------------------------------------------------------------------- 1 | const createProject = require('@poi/test-utils/createProject') 2 | 3 | jest.setTimeout(60000) 4 | 5 | test('astroturf', async () => { 6 | const project = await createProject({ name: 'astroturf' }) 7 | await project.write( 8 | '.poirc', 9 | JSON.stringify({ 10 | plugins: [require.resolve('.')], 11 | output: { 12 | format: 'cjs', 13 | target: 'node' 14 | } 15 | }) 16 | ) 17 | await project.write( 18 | 'index.js', 19 | ` 20 | import { css } from 'astroturf'; 21 | 22 | const margin = 10; 23 | const height = 50; 24 | const bottom = height + margin; 25 | 26 | const styles = css\` 27 | .box { 28 | height: \${height}px; 29 | margin-bottom: \${margin}px; 30 | } 31 | 32 | .footer { 33 | position: absolute; 34 | top: \${bottom}px; 35 | } 36 | \`; 37 | 38 | export default styles; 39 | ` 40 | ) 41 | await project.run('poi') 42 | expect(project.require('dist/index.js')).toEqual({ 43 | default: { 44 | box: 'index-styles.module_box_1SCdY', 45 | footer: 'index-styles.module_footer_1xrFU' 46 | } 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /plugins/astroturf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/plugin-astroturf", 3 | "version": "0.2.0", 4 | "main": "index.js", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "scripts": { 9 | "test": "jest --env node" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@poi/test-utils": "^12.0.2", 17 | "astroturf": "^0.9.2" 18 | }, 19 | "peerDependencies": { 20 | "astroturf": "^0.9.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugins/bundle-report/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [12.1.2](https://github.com/egoist/poi/compare/@poi/plugin-bundle-report@12.1.1...@poi/plugin-bundle-report@12.1.2) (2019-12-13) 7 | 8 | **Note:** Version bump only for package @poi/plugin-bundle-report 9 | 10 | ## [12.1.1](https://github.com/egoist/poi/compare/@poi/plugin-bundle-report@12.1.0...@poi/plugin-bundle-report@12.1.1) (2019-05-23) 11 | 12 | **Note:** Version bump only for package @poi/plugin-bundle-report 13 | 14 | # 12.1.0 (2019-02-06) 15 | 16 | ### Features 17 | 18 | - bundle report plugin ([#537](https://github.com/egoist/poi/issues/537)) ([318eb79](https://github.com/egoist/poi/commit/318eb79)), closes [/github.com/egoist/poi/issues/507#issuecomment-449032295](https://github.com//github.com/egoist/poi/issues/507/issues/issuecomment-449032295) 19 | -------------------------------------------------------------------------------- /plugins/bundle-report/README.md: -------------------------------------------------------------------------------- 1 | # @poi/plugin-bundle-report 2 | 3 | This is a preset for adding [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) which could help you: 4 | 5 | 1. Realize what's really inside your bundle 6 | 2. Find out what modules make up the most of it's size 7 | 3. Find modules that got there by mistake 8 | 4. Optimize it! 9 | 10 | ## Install 11 | 12 | ```bash 13 | yarn add @poi/plugin-bundle-report --dev 14 | ``` 15 | 16 | ## Usage 17 | 18 | Activate it in config file: 19 | 20 | ```js 21 | // poi.config.js 22 | module.exports = { 23 | plugins: [ 24 | { 25 | resolve: '@poi/bundle-report', 26 | options: {} 27 | } 28 | ] 29 | } 30 | ``` 31 | 32 | Add `--bundle-report` while building your app in **production mode** to get report: 33 | 34 | ```bash 35 | poi --prod --bundle-report 36 | # then you'll be automatically navigated to http://localhost:8888 37 | ``` 38 | 39 | ## Options 40 | Options object for [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) plugin. 41 | 42 | ## LICENSE 43 | 44 | MIT © [EGOIST](https://github.com/egoist) 45 | -------------------------------------------------------------------------------- /plugins/bundle-report/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // NOTE: This is adapted version of `poi-preset-bundle-report` updated to work 4 | // with poi@12 (original code: https://github.com/egoist/poi/tree/v9.2.0/packages/poi-preset-bundle-report) 5 | exports.name = 'bundle-report' 6 | 7 | exports.cli = api => { 8 | if (!api.isProd) return 9 | api.command.option('--bundle-report', 'View bundle report') 10 | } 11 | 12 | exports.apply = (api, options = {}) => { 13 | api.hook('createWebpackChain', config => { 14 | if (!api.cli.options.bundleReport) return 15 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') 16 | config.plugin('bundle-report').use(BundleAnalyzerPlugin, [options]) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /plugins/bundle-report/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/plugin-bundle-report", 3 | "version": "12.1.2", 4 | "main": "index.js", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "publishConfig": { 9 | "access": "public" 10 | }, 11 | "license": "MIT", 12 | "dependencies": { 13 | "webpack-bundle-analyzer": "^3.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /plugins/eslint/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [12.1.0](https://github.com/egoist/poi/compare/@poi/plugin-eslint@12.0.1...@poi/plugin-eslint@12.1.0) (2020-04-30) 7 | 8 | 9 | ### Features 10 | 11 | * **eslint:** Pass `loaderOptions` to `eslint-loader` ([#668](https://github.com/egoist/poi/issues/668)) ([9401965](https://github.com/egoist/poi/commit/9401965)) 12 | 13 | 14 | 15 | 16 | 17 | ## [12.0.1](https://github.com/egoist/poi/compare/@poi/plugin-eslint@12.0.0...@poi/plugin-eslint@12.0.1) (2019-12-13) 18 | 19 | **Note:** Version bump only for package @poi/plugin-eslint 20 | -------------------------------------------------------------------------------- /plugins/eslint/README.md: -------------------------------------------------------------------------------- 1 | # @poi/plugin-eslint 2 | 3 | Use ESLint to lint JavaScript. 4 | 5 | ## Install 6 | 7 | ```bash 8 | yarn add @poi/plugin-eslint --dev 9 | ``` 10 | 11 | ## How to use 12 | 13 | In your `poi.config.js`: 14 | 15 | ```js 16 | module.exports = { 17 | plugins: [ 18 | { 19 | resolve: '@poi/plugin-eslint' 20 | } 21 | ] 22 | } 23 | ``` 24 | 25 | Then add a `.eslintrc.js` in your project: 26 | 27 | ```js 28 | module.exports = { 29 | extends: ['eslint:recommended'] 30 | } 31 | ``` 32 | 33 | Now ESLint will check your JS files at compile time. 34 | 35 | 36 | ## Options 37 | 38 | ### loaderOptions 39 | 40 | - Type: `any` 41 | 42 | Addtional [options](https://github.com/webpack-contrib/eslint-loader#options) for `eslint-loader`. 43 | -------------------------------------------------------------------------------- /plugins/eslint/index.js: -------------------------------------------------------------------------------- 1 | exports.name = 'eslint' 2 | 3 | exports.apply = (api, options = {}) => { 4 | api.hook('createWebpackChain', config => { 5 | const { cacheIdentifier } = api.getCacheConfig('eslint-loader', {}, [ 6 | '.eslintrc.js', 7 | '.eslintrc.yaml', 8 | '.eslintrc.yml', 9 | '.eslintrc.json', 10 | '.eslintrc', 11 | 'package.json' 12 | ]) 13 | config.module 14 | .rule('eslint') 15 | .test([/\.jsx?$/, /\.vue$/]) 16 | .pre() 17 | .exclude.add(filepath => /node_modules/.test(filepath)) 18 | .end() 19 | .use('eslint-loader') 20 | .loader(require.resolve('eslint-loader')) 21 | .options({ 22 | formatter: require('eslint/lib/formatters/codeframe'), 23 | eslintPath: api.localResolve('eslint') || require.resolve('eslint'), 24 | ...options.loaderOptions, 25 | cache: api.config.cache, 26 | cacheKey: cacheIdentifier 27 | }) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /plugins/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@poi/plugin-eslint", 3 | "version": "12.1.0", 4 | "main": "index.js", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "publishConfig": { 9 | "access": "public" 10 | }, 11 | "license": "MIT", 12 | "dependencies": { 13 | "eslint": "^5.9.0", 14 | "eslint-formatter-pretty": "^2.0.0", 15 | "eslint-loader": "^3.0.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /plugins/html-entry/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.2.3](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.2.2...@poi/plugin-html-entry@0.2.3) (2020-07-13) 7 | 8 | **Note:** Version bump only for package @poi/plugin-html-entry 9 | 10 | ## [0.2.2](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.2.1...@poi/plugin-html-entry@0.2.2) (2020-04-30) 11 | 12 | **Note:** Version bump only for package @poi/plugin-html-entry 13 | 14 | ## [0.2.1](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.2.0...@poi/plugin-html-entry@0.2.1) (2019-08-09) 15 | 16 | ### Bug Fixes 17 | 18 | - **html-entry:** fix json assets support in html entry ([#619](https://github.com/egoist/poi/issues/619)) ([91dfd21](https://github.com/egoist/poi/commit/91dfd21)) 19 | 20 | # [0.2.0](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.1.4...@poi/plugin-html-entry@0.2.0) (2019-05-23) 21 | 22 | ### Bug Fixes 23 | 24 | - **html-entry:** support external css and scripts ([ff65156](https://github.com/egoist/poi/commit/ff65156)), closes [#570](https://github.com/egoist/poi/issues/570) [#571](https://github.com/egoist/poi/issues/571) 25 | 26 | ### Features 27 | 28 | - **html-entry:** a better way to handle static asset ([873cc16](https://github.com/egoist/poi/commit/873cc16)) 29 | - **html-entry:** support all link tags([#572](https://github.com/egoist/poi/issues/572)) ([5695f25](https://github.com/egoist/poi/commit/5695f25)) 30 | 31 | ## [0.1.4](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.1.3...@poi/plugin-html-entry@0.1.4) (2019-04-08) 32 | 33 | ### Bug Fixes 34 | 35 | - **html-entry:** slash attrs for static assets ([#558](https://github.com/egoist/poi/issues/558)) ([3a2bf0e](https://github.com/egoist/poi/commit/3a2bf0e)) 36 | 37 | ## [0.1.3](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.1.2...@poi/plugin-html-entry@0.1.3) (2019-04-06) 38 | 39 | ### Bug Fixes 40 | 41 | - **html-entry:** convert backslash to slash ([b1f581c](https://github.com/egoist/poi/commit/b1f581c)), closes [#555](https://github.com/egoist/poi/issues/555) 42 | 43 | ## [0.1.2](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.1.1...@poi/plugin-html-entry@0.1.2) (2019-03-12) 44 | 45 | ### Bug Fixes 46 | 47 | - **html-entry:** es5-ify generated files ([8df9835](https://github.com/egoist/poi/commit/8df9835)) 48 | 49 | ## [0.1.1](https://github.com/egoist/poi/compare/@poi/plugin-html-entry@0.1.0...@poi/plugin-html-entry@0.1.1) (2019-01-24) 50 | 51 | ### Bug Fixes 52 | 53 | - **html-entry:** remove unnecessary dependency ([48eb88f](https://github.com/egoist/poi/commit/48eb88f)) 54 | 55 | # 0.1.0 (2019-01-24) 56 | 57 | ### Features 58 | 59 | - support html an entry file ([289468a](https://github.com/egoist/poi/commit/289468a)) 60 | - support html file as entrypoint ([bdf5359](https://github.com/egoist/poi/commit/bdf5359)) 61 | -------------------------------------------------------------------------------- /plugins/html-entry/README.md: -------------------------------------------------------------------------------- 1 | # @poi/plugin-html-entry 2 | 3 | This is a built-in Poi plugin which makes Poi support HTML entrypoint. 4 | 5 | ## Features 6 | 7 | ### Process local scripts and styles 8 | 9 | ```html 10 | 11 | 12 | ``` 13 | 14 | Note that only relative paths will be processed by webpack, which means you can use absolute paths like `https://...` or `/static/foo.css` to reference external resources. 15 | 16 | ### Process certain HTML attributes 17 | 18 | It processes certain HTML attributes: 19 | 20 | - ``: `src` 21 | - ``: `xlink:href` 22 | - `