├── .circleci
└── config.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── funding.yml
├── .gitignore
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── codecov.yml
├── commitlint.config.js
├── lib
├── client.js
├── index.js
├── middleware.js
└── validate.js
├── package-lock.json
├── package.json
└── test
├── fixtures
├── input.js
└── webpack.config.js
└── test.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | dependency_cache:
4 | docker:
5 | - image: rollupcabal/circleci-node-base:latest
6 | steps:
7 | - checkout
8 | - restore_cache:
9 | key: dependency-cache-{{ checksum "package-lock.json" }}
10 | - run:
11 | name: Install Dependencies
12 | command: npm install
13 | - save_cache:
14 | key: dependency-cache-{{ checksum "package-lock.json" }}
15 | paths:
16 | - ./node_modules
17 | node-v10-latest:
18 | docker:
19 | - image: rollupcabal/circleci-node-v10:latest
20 | steps:
21 | - checkout
22 | - restore_cache:
23 | key: dependency-cache-{{ checksum "package-lock.json" }}
24 | - run:
25 | name: NPM Rebuild
26 | command: npm install
27 | - run:
28 | name: Run unit tests.
29 | command: npm run ci:test
30 | node-v12-latest:
31 | docker:
32 | - image: rollupcabal/circleci-node-v12:latest
33 | steps:
34 | - checkout
35 | - restore_cache:
36 | key: dependency-cache-{{ checksum "package-lock.json" }}
37 | - run:
38 | name: NPM Rebuild
39 | command: npm install
40 | - run:
41 | name: Run unit tests.
42 | command: npm run ci:coverage
43 | - run:
44 | name: Submit coverage data to codecov.
45 | command: bash <(curl -s https://codecov.io/bash)
46 | when: on_success
47 | analysis:
48 | docker:
49 | - image: rollupcabal/circleci-node-base:latest
50 | steps:
51 | - checkout
52 | - restore_cache:
53 | key: dependency-cache-{{ checksum "package-lock.json" }}
54 | - run:
55 | name: NPM Rebuild
56 | command: npm install
57 | - run:
58 | name: Run linting.
59 | command: npm run lint
60 | - run:
61 | name: Run Security Check
62 | command: npm run security
63 | - run:
64 | name: Validate Commit Messages
65 | command: npm run ci:lint:commits
66 | workflows:
67 | version: 2
68 | validate:
69 | jobs:
70 | - dependency_cache
71 | - analysis:
72 | requires:
73 | - dependency_cache
74 | filters:
75 | tags:
76 | only: /.*/
77 | - node-v10-latest:
78 | requires:
79 | - analysis
80 | filters:
81 | tags:
82 | only: /.*/
83 | - node-v12-latest:
84 | requires:
85 | - analysis
86 | filters:
87 | tags:
88 | only: /.*/
89 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | insert_final_newline = false
13 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /dist
3 | index-old.js
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "shellscape",
3 | "globals": {
4 | "document": true,
5 | "WebSocket": true,
6 | "window": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | package-lock.json -diff
2 | * text=auto
3 | bin/* eol=lf
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Welcome!
2 | > Thanks ahead for taking the time to contribute to this project
3 |
4 | ## What We Use
5 |
6 | - Testing: [Ava](https://github.com/avajs/ava)
7 | - Linting: [ESLint](http://eslint.org/)
8 | - Building: [Webpack](https://webpack.github.io/)
9 |
10 | ## Pull Requests
11 |
12 | Please don't commit `package-lock.json`.
13 |
14 | Please don't change variable or parameter names to match your
15 | personal prefrences, unless the change is part of a refactor
16 | or significant modification of the codebase (which is very rare).
17 |
18 | Please remember to thoroughly explain your Pull Request if it
19 | doesn't have an associated issue. If you're changing code
20 | significantly, please remember to add inline or block comments
21 | in the code as appropriate.
22 |
23 | ## Thanks
24 |
25 | For your interest, understanding, and for following this simple guide.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | > The Issues page for this repository is not a support forum, it is for reporting potential bugs in this module, which
2 | [composes](https://github.com/koajs/compose) webpack-hot-middleware and webpack-dev-middle for use with koa2.
3 | If you have arrived here because you cannot get [webpack-hot-middleware](https://github.com/glenjamin/webpack-hot-middlewar)
4 | or [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware/) working, please review the documentation
5 | for the respective middleware you are experiencing a problem with. If you proceed with this form, please fill out *_all_* fields, or your issue may be closed as "invalid." Please remove this header to acknowledge this message.
6 |
7 | * Node Version:
8 | * NPM Version:
9 | * koa Version:
10 | * koa-wepback Version:
11 |
12 | If you have a large amount of code to share which demonstrates the problem you're experiencing, please provide a link to your
13 | repository rather than pasting code. Otherwise, please paste relevant short snippets below.
14 |
15 | ```js
16 | // webpack.config.js
17 | ```
18 |
19 | ```js
20 | // app.js
21 | ```
22 |
23 | ### Expected Behavior
24 |
25 | ### Actual Behavior
26 |
27 | ### How can we reproduce the behavior?
28 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | This PR contains a:
12 |
13 | - [ ] **bugfix**
14 | - [ ] new **feature**
15 | - [ ] **code refactor**
16 | - [ ] **test update**
17 | - [ ] **typo fix**
18 | - [ ] **metadata update**
19 |
20 | ### Motivation / Use-Case
21 |
22 |
27 |
28 | ### Breaking Changes
29 |
30 |
34 |
35 | ### Additional Info
--------------------------------------------------------------------------------
/.github/funding.yml:
--------------------------------------------------------------------------------
1 | patreon: shellscape
2 | custom: https://paypal.me/shellscape
3 | liberapay: shellscape
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | npm-debug.log
3 | coverage
4 | node_modules
5 |
6 | .nyc_output
7 | coverage.lcov
8 |
9 | .eslintcache
10 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "arrowParens": "always"
5 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Andrew Powell
2 |
3 | Mozilla Public License Version 2.0
4 | ==================================
5 |
6 | 1. Definitions
7 | --------------
8 |
9 | 1.1. "Contributor"
10 | means each individual or legal entity that creates, contributes to
11 | the creation of, or owns Covered Software.
12 |
13 | 1.2. "Contributor Version"
14 | means the combination of the Contributions of others (if any) used
15 | by a Contributor and that particular Contributor's Contribution.
16 |
17 | 1.3. "Contribution"
18 | means Covered Software of a particular Contributor.
19 |
20 | 1.4. "Covered Software"
21 | means Source Code Form to which the initial Contributor has attached
22 | the notice in Exhibit A, the Executable Form of such Source Code
23 | Form, and Modifications of such Source Code Form, in each case
24 | including portions thereof.
25 |
26 | 1.5. "Incompatible With Secondary Licenses"
27 | means
28 |
29 | (a) that the initial Contributor has attached the notice described
30 | in Exhibit B to the Covered Software; or
31 |
32 | (b) that the Covered Software was made available under the terms of
33 | version 1.1 or earlier of the License, but not also under the
34 | terms of a Secondary License.
35 |
36 | 1.6. "Executable Form"
37 | means any form of the work other than Source Code Form.
38 |
39 | 1.7. "Larger Work"
40 | means a work that combines Covered Software with other material, in
41 | a separate file or files, that is not Covered Software.
42 |
43 | 1.8. "License"
44 | means this document.
45 |
46 | 1.9. "Licensable"
47 | means having the right to grant, to the maximum extent possible,
48 | whether at the time of the initial grant or subsequently, any and
49 | all of the rights conveyed by this License.
50 |
51 | 1.10. "Modifications"
52 | means any of the following:
53 |
54 | (a) any file in Source Code Form that results from an addition to,
55 | deletion from, or modification of the contents of Covered
56 | Software; or
57 |
58 | (b) any new file in Source Code Form that contains any Covered
59 | Software.
60 |
61 | 1.11. "Patent Claims" of a Contributor
62 | means any patent claim(s), including without limitation, method,
63 | process, and apparatus claims, in any patent Licensable by such
64 | Contributor that would be infringed, but for the grant of the
65 | License, by the making, using, selling, offering for sale, having
66 | made, import, or transfer of either its Contributions or its
67 | Contributor Version.
68 |
69 | 1.12. "Secondary License"
70 | means either the GNU General Public License, Version 2.0, the GNU
71 | Lesser General Public License, Version 2.1, the GNU Affero General
72 | Public License, Version 3.0, or any later versions of those
73 | licenses.
74 |
75 | 1.13. "Source Code Form"
76 | means the form of the work preferred for making modifications.
77 |
78 | 1.14. "You" (or "Your")
79 | means an individual or a legal entity exercising rights under this
80 | License. For legal entities, "You" includes any entity that
81 | controls, is controlled by, or is under common control with You. For
82 | purposes of this definition, "control" means (a) the power, direct
83 | or indirect, to cause the direction or management of such entity,
84 | whether by contract or otherwise, or (b) ownership of more than
85 | fifty percent (50%) of the outstanding shares or beneficial
86 | ownership of such entity.
87 |
88 | 2. License Grants and Conditions
89 | --------------------------------
90 |
91 | 2.1. Grants
92 |
93 | Each Contributor hereby grants You a world-wide, royalty-free,
94 | non-exclusive license:
95 |
96 | (a) under intellectual property rights (other than patent or trademark)
97 | Licensable by such Contributor to use, reproduce, make available,
98 | modify, display, perform, distribute, and otherwise exploit its
99 | Contributions, either on an unmodified basis, with Modifications, or
100 | as part of a Larger Work; and
101 |
102 | (b) under Patent Claims of such Contributor to make, use, sell, offer
103 | for sale, have made, import, and otherwise transfer either its
104 | Contributions or its Contributor Version.
105 |
106 | 2.2. Effective Date
107 |
108 | The licenses granted in Section 2.1 with respect to any Contribution
109 | become effective for each Contribution on the date the Contributor first
110 | distributes such Contribution.
111 |
112 | 2.3. Limitations on Grant Scope
113 |
114 | The licenses granted in this Section 2 are the only rights granted under
115 | this License. No additional rights or licenses will be implied from the
116 | distribution or licensing of Covered Software under this License.
117 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
118 | Contributor:
119 |
120 | (a) for any code that a Contributor has removed from Covered Software;
121 | or
122 |
123 | (b) for infringements caused by: (i) Your and any other third party's
124 | modifications of Covered Software, or (ii) the combination of its
125 | Contributions with other software (except as part of its Contributor
126 | Version); or
127 |
128 | (c) under Patent Claims infringed by Covered Software in the absence of
129 | its Contributions.
130 |
131 | This License does not grant any rights in the trademarks, service marks,
132 | or logos of any Contributor (except as may be necessary to comply with
133 | the notice requirements in Section 3.4).
134 |
135 | 2.4. Subsequent Licenses
136 |
137 | No Contributor makes additional grants as a result of Your choice to
138 | distribute the Covered Software under a subsequent version of this
139 | License (see Section 10.2) or under the terms of a Secondary License (if
140 | permitted under the terms of Section 3.3).
141 |
142 | 2.5. Representation
143 |
144 | Each Contributor represents that the Contributor believes its
145 | Contributions are its original creation(s) or it has sufficient rights
146 | to grant the rights to its Contributions conveyed by this License.
147 |
148 | 2.6. Fair Use
149 |
150 | This License is not intended to limit any rights You have under
151 | applicable copyright doctrines of fair use, fair dealing, or other
152 | equivalents.
153 |
154 | 2.7. Conditions
155 |
156 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
157 | in Section 2.1.
158 |
159 | 3. Responsibilities
160 | -------------------
161 |
162 | 3.1. Distribution of Source Form
163 |
164 | All distribution of Covered Software in Source Code Form, including any
165 | Modifications that You create or to which You contribute, must be under
166 | the terms of this License. You must inform recipients that the Source
167 | Code Form of the Covered Software is governed by the terms of this
168 | License, and how they can obtain a copy of this License. You may not
169 | attempt to alter or restrict the recipients' rights in the Source Code
170 | Form.
171 |
172 | 3.2. Distribution of Executable Form
173 |
174 | If You distribute Covered Software in Executable Form then:
175 |
176 | (a) such Covered Software must also be made available in Source Code
177 | Form, as described in Section 3.1, and You must inform recipients of
178 | the Executable Form how they can obtain a copy of such Source Code
179 | Form by reasonable means in a timely manner, at a charge no more
180 | than the cost of distribution to the recipient; and
181 |
182 | (b) You may distribute such Executable Form under the terms of this
183 | License, or sublicense it under different terms, provided that the
184 | license for the Executable Form does not attempt to limit or alter
185 | the recipients' rights in the Source Code Form under this License.
186 |
187 | 3.3. Distribution of a Larger Work
188 |
189 | You may create and distribute a Larger Work under terms of Your choice,
190 | provided that You also comply with the requirements of this License for
191 | the Covered Software. If the Larger Work is a combination of Covered
192 | Software with a work governed by one or more Secondary Licenses, and the
193 | Covered Software is not Incompatible With Secondary Licenses, this
194 | License permits You to additionally distribute such Covered Software
195 | under the terms of such Secondary License(s), so that the recipient of
196 | the Larger Work may, at their option, further distribute the Covered
197 | Software under the terms of either this License or such Secondary
198 | License(s).
199 |
200 | 3.4. Notices
201 |
202 | You may not remove or alter the substance of any license notices
203 | (including copyright notices, patent notices, disclaimers of warranty,
204 | or limitations of liability) contained within the Source Code Form of
205 | the Covered Software, except that You may alter any license notices to
206 | the extent required to remedy known factual inaccuracies.
207 |
208 | 3.5. Application of Additional Terms
209 |
210 | You may choose to offer, and to charge a fee for, warranty, support,
211 | indemnity or liability obligations to one or more recipients of Covered
212 | Software. However, You may do so only on Your own behalf, and not on
213 | behalf of any Contributor. You must make it absolutely clear that any
214 | such warranty, support, indemnity, or liability obligation is offered by
215 | You alone, and You hereby agree to indemnify every Contributor for any
216 | liability incurred by such Contributor as a result of warranty, support,
217 | indemnity or liability terms You offer. You may include additional
218 | disclaimers of warranty and limitations of liability specific to any
219 | jurisdiction.
220 |
221 | 4. Inability to Comply Due to Statute or Regulation
222 | ---------------------------------------------------
223 |
224 | If it is impossible for You to comply with any of the terms of this
225 | License with respect to some or all of the Covered Software due to
226 | statute, judicial order, or regulation then You must: (a) comply with
227 | the terms of this License to the maximum extent possible; and (b)
228 | describe the limitations and the code they affect. Such description must
229 | be placed in a text file included with all distributions of the Covered
230 | Software under this License. Except to the extent prohibited by statute
231 | or regulation, such description must be sufficiently detailed for a
232 | recipient of ordinary skill to be able to understand it.
233 |
234 | 5. Termination
235 | --------------
236 |
237 | 5.1. The rights granted under this License will terminate automatically
238 | if You fail to comply with any of its terms. However, if You become
239 | compliant, then the rights granted under this License from a particular
240 | Contributor are reinstated (a) provisionally, unless and until such
241 | Contributor explicitly and finally terminates Your grants, and (b) on an
242 | ongoing basis, if such Contributor fails to notify You of the
243 | non-compliance by some reasonable means prior to 60 days after You have
244 | come back into compliance. Moreover, Your grants from a particular
245 | Contributor are reinstated on an ongoing basis if such Contributor
246 | notifies You of the non-compliance by some reasonable means, this is the
247 | first time You have received notice of non-compliance with this License
248 | from such Contributor, and You become compliant prior to 30 days after
249 | Your receipt of the notice.
250 |
251 | 5.2. If You initiate litigation against any entity by asserting a patent
252 | infringement claim (excluding declaratory judgment actions,
253 | counter-claims, and cross-claims) alleging that a Contributor Version
254 | directly or indirectly infringes any patent, then the rights granted to
255 | You by any and all Contributors for the Covered Software under Section
256 | 2.1 of this License shall terminate.
257 |
258 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
259 | end user license agreements (excluding distributors and resellers) which
260 | have been validly granted by You or Your distributors under this License
261 | prior to termination shall survive termination.
262 |
263 | ************************************************************************
264 | * *
265 | * 6. Disclaimer of Warranty *
266 | * ------------------------- *
267 | * *
268 | * Covered Software is provided under this License on an "as is" *
269 | * basis, without warranty of any kind, either expressed, implied, or *
270 | * statutory, including, without limitation, warranties that the *
271 | * Covered Software is free of defects, merchantable, fit for a *
272 | * particular purpose or non-infringing. The entire risk as to the *
273 | * quality and performance of the Covered Software is with You. *
274 | * Should any Covered Software prove defective in any respect, You *
275 | * (not any Contributor) assume the cost of any necessary servicing, *
276 | * repair, or correction. This disclaimer of warranty constitutes an *
277 | * essential part of this License. No use of any Covered Software is *
278 | * authorized under this License except under this disclaimer. *
279 | * *
280 | ************************************************************************
281 |
282 | ************************************************************************
283 | * *
284 | * 7. Limitation of Liability *
285 | * -------------------------- *
286 | * *
287 | * Under no circumstances and under no legal theory, whether tort *
288 | * (including negligence), contract, or otherwise, shall any *
289 | * Contributor, or anyone who distributes Covered Software as *
290 | * permitted above, be liable to You for any direct, indirect, *
291 | * special, incidental, or consequential damages of any character *
292 | * including, without limitation, damages for lost profits, loss of *
293 | * goodwill, work stoppage, computer failure or malfunction, or any *
294 | * and all other commercial damages or losses, even if such party *
295 | * shall have been informed of the possibility of such damages. This *
296 | * limitation of liability shall not apply to liability for death or *
297 | * personal injury resulting from such party's negligence to the *
298 | * extent applicable law prohibits such limitation. Some *
299 | * jurisdictions do not allow the exclusion or limitation of *
300 | * incidental or consequential damages, so this exclusion and *
301 | * limitation may not apply to You. *
302 | * *
303 | ************************************************************************
304 |
305 | 8. Litigation
306 | -------------
307 |
308 | Any litigation relating to this License may be brought only in the
309 | courts of a jurisdiction where the defendant maintains its principal
310 | place of business and such litigation shall be governed by laws of that
311 | jurisdiction, without reference to its conflict-of-law provisions.
312 | Nothing in this Section shall prevent a party's ability to bring
313 | cross-claims or counter-claims.
314 |
315 | 9. Miscellaneous
316 | ----------------
317 |
318 | This License represents the complete agreement concerning the subject
319 | matter hereof. If any provision of this License is held to be
320 | unenforceable, such provision shall be reformed only to the extent
321 | necessary to make it enforceable. Any law or regulation which provides
322 | that the language of a contract shall be construed against the drafter
323 | shall not be used to construe this License against a Contributor.
324 |
325 | 10. Versions of the License
326 | ---------------------------
327 |
328 | 10.1. New Versions
329 |
330 | Mozilla Foundation is the license steward. Except as provided in Section
331 | 10.3, no one other than the license steward has the right to modify or
332 | publish new versions of this License. Each version will be given a
333 | distinguishing version number.
334 |
335 | 10.2. Effect of New Versions
336 |
337 | You may distribute the Covered Software under the terms of the version
338 | of the License under which You originally received the Covered Software,
339 | or under the terms of any subsequent version published by the license
340 | steward.
341 |
342 | 10.3. Modified Versions
343 |
344 | If you create software not governed by this License, and you want to
345 | create a new license for such software, you may create and use a
346 | modified version of this License if you rename the license and remove
347 | any references to the name of the license steward (except to note that
348 | such modified license differs from this License).
349 |
350 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
351 | Licenses
352 |
353 | If You choose to distribute Source Code Form that is Incompatible With
354 | Secondary Licenses under the terms of this version of the License, the
355 | notice described in Exhibit B of this License must be attached.
356 |
357 | Exhibit A - Source Code Form License Notice
358 | -------------------------------------------
359 |
360 | This Source Code Form is subject to the terms of the Mozilla Public
361 | License, v. 2.0. If a copy of the MPL was not distributed with this
362 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
363 |
364 | If it is not possible or desirable to put the notice in a particular
365 | file, then You may include the notice in a location (such as a LICENSE
366 | file in a relevant directory) where a recipient would be likely to look
367 | for such a notice.
368 |
369 | You may add additional accurate notices of copyright ownership.
370 |
371 | Exhibit B - "Incompatible With Secondary Licenses" Notice
372 | ---------------------------------------------------------
373 |
374 | This Source Code Form is "Incompatible With Secondary Licenses", as
375 | defined by the Mozilla Public License, v. 2.0.
376 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [tests]: https://img.shields.io/circleci/project/github/shellscape/koa-webpack.svg
2 | [tests-url]: https://circleci.com/gh/shellscape/koa-webpack
3 |
4 | [cover]: https://codecov.io/gh/shellscape/koa-webpack/branch/master/graph/badge.svg
5 | [cover-url]: https://codecov.io/gh/shellscape/koa-webpack
6 |
7 | [size]: https://packagephobia.now.sh/badge?p=koa-webpack
8 | [size-url]: https://packagephobia.now.sh/result?p=koa-webpack
9 |
10 | # koa-webpack
11 |
12 | [![tests][tests]][tests-url]
13 | [![cover][cover]][cover-url]
14 | [![size][size]][size-url]
15 |
16 | Development and Hot Module Reload Middleware for **Koa2**, in a single
17 | middleware module.
18 |
19 | This module wraps and composes
20 | [`webpack-dev-middleware`](https://github.com/webpack/webpack-dev-middleware) and
21 | [`webpack-hot-client`](https://github.com/shellscape/webpack-hot-client)
22 | into a single middleware module, allowing for quick and concise implementation.
23 |
24 | As an added bonus, it'll also use the installed `webpack` module from your project,
25 | and the `webpack.config.js` file in the root of your project, automagically, should
26 | you choose to let it. This negates the need for all of the repetitive setup and
27 | config that you get with `koa-webpack-middleware`.
28 |
29 | ## Install
30 |
31 | Using npm:
32 |
33 | ```console
34 | npm install koa-webpack --save-dev
35 | ```
36 |
37 |
38 |
39 |
40 |
41 | ## Requirements
42 |
43 | `koa-webpack` is an evergreen module. 🌲 This module requires an [Active LTS](https://github.com/nodejs/Release) Node version (v8.0.0+ or v10.0.0+), and Webpack v4.0.0+.
44 |
45 | ## Usage
46 |
47 | ```js
48 | const Koa = require('koa');
49 | const koaWebpack = require('koa-webpack');
50 |
51 | const app = new Koa();
52 | const options = { .. };
53 | const middleware = await koaWebpack(options);
54 |
55 | app.use(middleware);
56 | ```
57 |
58 | ## API
59 |
60 | ### koaWebpack([options])
61 |
62 | Returns a `Promise` which resolves the server `middleware` containing the
63 | following additional properties:
64 |
65 | - `close(callback)` *(Function)* - Closes both the instance of `webpack-dev-middleware`
66 | and `webpack-hot-client`. Accepts a single `Function` callback parameter that is
67 | executed when complete.
68 | - `hotClient` *(Object)* - An instance of `webpack-hot-client`.
69 | - `devMiddleware` *(Object)* - An instance of `webpack-dev-middleware`
70 |
71 | ## Options
72 |
73 | The middleware accepts an `options` Object, which can contain options for the
74 | `webpack-dev-middleware` and `webpack-hot-client` bundled with this module.
75 | The following is a property reference for the Object:
76 |
77 | ### compiler
78 |
79 | Type: `Object`
80 | `optional`
81 |
82 | Should you rather that the middleware use an instance of `webpack` that you've
83 | already init'd [with webpack config], you can pass it to the middleware using
84 | this option.
85 |
86 | Example:
87 |
88 | ```js
89 | const webpack = require('webpack');
90 | const config = require('./webpack.config.js');
91 | const koaWebpack = require('koa-webpack');
92 |
93 | const compiler = webpack(config);
94 | const middleware = await koaWebpack({ compiler });
95 |
96 | app.use(middleware);
97 | ```
98 |
99 | ### config
100 |
101 | Type: `Object`
102 |
103 | Should you rather that the middleware use an instance of webpack configuration
104 | that you've already required/imported, you can pass it to the middleware using
105 | this option.
106 |
107 | Example:
108 |
109 | ```js
110 | const koaWebpack = require('koa-webpack');
111 | const config = require('./webpack.config.js');
112 |
113 | const middleware = await koaWebpack({ config });
114 |
115 | app.use(middleware);
116 | ```
117 |
118 | ### configPath
119 |
120 | Type: `String`
121 |
122 | Allows you to specify the absolute path to the Webpack config file to be used.
123 |
124 | Example:
125 |
126 | ```js
127 | const path = require('path');
128 | const koaWebpack = require('koa-webpack');
129 |
130 | // The Webpack config file would be at "./client/webpack.config.js".
131 | const middleware = await koaWebpack({
132 | configPath: path.join(__dirname, 'client', 'webpack.config.js')
133 | });
134 |
135 | app.use(middleware);
136 | ```
137 |
138 | ### devMiddleware
139 |
140 | Type: `Object`
141 |
142 | The `devMiddleware` property should contain options for `webpack-dev-middleware`, a list of
143 | which is available at [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware).
144 | Omitting this property will result in `webpack-dev-middleware` using its default
145 | options.
146 |
147 | ### hotClient
148 |
149 | Type: `Object|Boolean`
150 |
151 | The `hotClient` property should contain options for `webpack-hot-client`, a list of
152 | which is available at [webpack-hot-client](https://github.com/webpack-contrib/webpack-hot-client).
153 | Omitting this property will result in `webpack-hot-client` using its default
154 | options.
155 |
156 | As of `v3.0.1` setting this to `false` will completely disable `webpack-hot-client`
157 | and all automatic Hot Module Replacement functionality.
158 |
159 | ## Using with koa-compress
160 |
161 | When using `koa-webpack` with [koa-compress](https://github.com/koajs/compress),
162 | you may experience issues with saving files and hot module reload. Please review
163 | [this issue](https://github.com/shellscape/koa-webpack/issues/36#issuecomment-289565573)
164 | for more information and a workaround.
165 |
166 | ## Server-Side-Rendering
167 |
168 | When `serverSideRender` is set to true in `config.devMiddleware`, `webpackStats` is
169 | accessible from `ctx.state.webpackStats`.
170 |
171 | ```js
172 | app.use(async (ctx, next) => {
173 | const assetsByChunkName = ctx.state.webpackStats.toJson().assetsByChunkName;
174 | // do something with assetsByChunkName
175 | })
176 | ```
177 |
178 | For more details please refer to:
179 | [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware#server-side-rendering)
180 |
181 |
182 | ## Using with html-webpack-plugin
183 |
184 | When using with html-webpack-plugin, you can access dev-middleware in-memory filesystem to serve index.html file:
185 |
186 | ```js
187 | const middleware = await koaWebpack({ config });
188 |
189 | app.use(middleware);
190 |
191 | app.use(async (ctx) => {
192 | const filename = path.resolve(webpackConfig.output.path, 'index.html')
193 | ctx.response.type = 'html'
194 | ctx.response.body = middleware.devMiddleware.fileSystem.createReadStream(filename)
195 | });
196 | ```
197 |
198 | ## Contributing
199 |
200 | Please take a moment to read our contributing guidelines if you haven't yet done so.
201 |
202 | #### [CONTRIBUTING](./.github/CONTRIBUTING.md)
203 |
204 | ## Attribution
205 |
206 | This module started as a fork of
207 | [`koa-webpack-middleware`](https://github.com/leecade/koa-webpack-middleware)
208 |
209 | ## License
210 |
211 | #### [MPL](./LICENSE)
212 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: master
3 | coverage:
4 | precision: 2
5 | round: down
6 | range: 70...100
7 | status:
8 | project: 'no'
9 | patch: 'yes'
10 | comment: 'off'
11 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const Configuration = {
3 | rules: {
4 | 'body-leading-blank': [1, 'always'],
5 | 'footer-leading-blank': [1, 'always'],
6 | 'header-max-length': [2, 'always', 72],
7 | 'scope-case': [2, 'always', 'lower-case'],
8 | 'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']],
9 | 'subject-empty': [2, 'never'],
10 | 'subject-full-stop': [2, 'never', '.'],
11 | 'type-case': [2, 'always', 'lower-case'],
12 | 'type-empty': [2, 'never'],
13 | 'type-enum': [2, 'always', [
14 | 'build',
15 | 'chore',
16 | 'ci',
17 | 'docs',
18 | 'feat',
19 | 'fix',
20 | 'perf',
21 | 'refactor',
22 | 'revert',
23 | 'style',
24 | 'test',
25 | ],
26 | ],
27 | },
28 | };
29 |
30 | module.exports = Configuration;
31 |
--------------------------------------------------------------------------------
/lib/client.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2016 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | const webpackHotClient = require('webpack-hot-client');
12 |
13 | module.exports = {
14 | getClient(compiler, options) {
15 | if (!options.hotClient) {
16 | return Promise.resolve(null);
17 | }
18 |
19 | return new Promise((resolve) => {
20 | const client = webpackHotClient(compiler, options.hotClient);
21 | const { server } = client;
22 |
23 | server.on('listening', () => resolve(client));
24 | });
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2016 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | const { join } = require('path');
12 |
13 | const root = require('app-root-path');
14 | const chalk = require('chalk');
15 | const webpack = require('webpack');
16 | const webpackDevMiddleware = require('webpack-dev-middleware');
17 |
18 | const { getClient } = require('./client');
19 | const { getMiddleware } = require('./middleware');
20 | const { validate } = require('./validate');
21 |
22 | const defaults = { devMiddleware: {}, hotClient: {} };
23 |
24 | module.exports = async (opts) => {
25 | const valid = validate(opts);
26 |
27 | if (valid.error) {
28 | const { error } = console;
29 | error(chalk.red('⬢ koa-webpack:'), 'An option was passed to koa-webpack that is not valid');
30 | throw valid.error;
31 | }
32 |
33 | const options = Object.assign({}, defaults, opts);
34 |
35 | let { compiler, config } = options;
36 |
37 | if (!compiler) {
38 | if (!config) {
39 | // eslint-disable-next-line import/no-dynamic-require, global-require
40 | config = require(options.configPath || join(root.path, 'webpack.config.js'));
41 | }
42 |
43 | compiler = webpack(config);
44 | }
45 |
46 | if (!options.devMiddleware.publicPath) {
47 | const { publicPath } = compiler.options.output;
48 |
49 | if (!publicPath) {
50 | throw new Error(
51 | "koa-webpack: publicPath must be set on `dev` options, or in a compiler's `output` configuration."
52 | );
53 | }
54 |
55 | options.devMiddleware.publicPath = publicPath;
56 | }
57 |
58 | const hotClient = await getClient(compiler, options);
59 | const devMiddleware = webpackDevMiddleware(compiler, options.devMiddleware);
60 | const middleware = getMiddleware(compiler, devMiddleware);
61 | const close = (callback) => {
62 | const next = hotClient ? () => hotClient.close(callback) : callback;
63 | devMiddleware.close(next);
64 | };
65 |
66 | return Object.assign(middleware, {
67 | hotClient,
68 | devMiddleware,
69 | close
70 | });
71 | };
72 |
--------------------------------------------------------------------------------
/lib/middleware.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2016 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | module.exports = {
12 | getMiddleware(compiler, devMiddleware) {
13 | return (context, next) => {
14 | // wait for webpack-dev-middleware to signal that the build is ready
15 | const ready = new Promise((resolve, reject) => {
16 | for (const comp of [].concat(compiler.compilers || compiler)) {
17 | comp.hooks.failed.tap('KoaWebpack', (error) => {
18 | reject(error);
19 | });
20 | }
21 |
22 | devMiddleware.waitUntilValid(() => {
23 | resolve(true);
24 | });
25 | });
26 | // tell webpack-dev-middleware to handle the request
27 | const init = new Promise((resolve) => {
28 | devMiddleware(
29 | context.req,
30 | {
31 | end: (content) => {
32 | // eslint-disable-next-line no-param-reassign
33 | context.body = content;
34 | resolve();
35 | },
36 | getHeader: context.get.bind(context),
37 | setHeader: context.set.bind(context),
38 | locals: context.state
39 | },
40 | () => resolve(next())
41 | );
42 | });
43 |
44 | return Promise.all([ready, init]);
45 | };
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/lib/validate.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2016 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | const Joi = require('joi');
12 |
13 | module.exports = {
14 | validate(options) {
15 | const keys = {
16 | compiler: [Joi.object().allow(null)],
17 | config: [Joi.object().allow(null)],
18 | configPath: [Joi.string().allow(null)],
19 | devMiddleware: [Joi.object()],
20 | hotClient: [Joi.boolean(), Joi.object().allow(null)]
21 | };
22 | const schema = Joi.object().keys(keys);
23 | const results = schema.validate(options);
24 |
25 | return results;
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "koa-webpack",
3 | "version": "6.0.0",
4 | "description": "Development and Hot Reload Middleware for Koa2",
5 | "license": "MPL-2.0",
6 | "repository": "shellscape/koa-webpack",
7 | "author": "Andrew Powell ",
8 | "homepage": "https://github.com/shellscape/koa-webpack",
9 | "bugs": "https://github.com/shellscape/koa-webpack/issues",
10 | "main": "lib/index.js",
11 | "engines": {
12 | "node": ">= 10.0.0"
13 | },
14 | "scripts": {
15 | "ci:coverage": "nyc npm run ci:test && nyc report --reporter=text-lcov > coverage.lcov",
16 | "ci:lint": "npm run lint && npm run security",
17 | "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}",
18 | "ci:test": "npm run test -- --verbose",
19 | "lint": "eslint --fix --cache lib test",
20 | "lint-staged": "lint-staged",
21 | "security": "npm audit --audit-level=high",
22 | "test": "ava --timeout=2500"
23 | },
24 | "files": [
25 | "lib/",
26 | "LICENSE",
27 | "README.md"
28 | ],
29 | "peerDependencies": {
30 | "webpack": "^4.28.0"
31 | },
32 | "dependencies": {
33 | "app-root-path": "^3.0.0",
34 | "chalk": "^4.1.0",
35 | "joi": "^17.2.0",
36 | "merge-options": "^2.0.0",
37 | "webpack-dev-middleware": "^3.7.2",
38 | "webpack-hot-client": "^4.1.2"
39 | },
40 | "devDependencies": {
41 | "@commitlint/cli": "^9.1.2",
42 | "ava": "^3.11.1",
43 | "eslint": "^6.0.1",
44 | "eslint-config-shellscape": "^2.1.0",
45 | "husky": "^4.2.5",
46 | "killable": "^1.0.1",
47 | "koa": "^2.13.0",
48 | "koa-compose": "^4.1.0",
49 | "lint-staged": "^10.2.11",
50 | "nyc": "^15.1.0",
51 | "pre-commit": "^1.2.2",
52 | "prettier": "^1.13.4",
53 | "supertest": "^4.0.2",
54 | "webpack": "^4.44.1"
55 | },
56 | "keywords": [
57 | "koa",
58 | "middleware",
59 | "webpack"
60 | ],
61 | "ava": {
62 | "files": [
63 | "!**/fixtures/**",
64 | "!**/helpers/**"
65 | ]
66 | },
67 | "lint-staged": {
68 | "*.js": [
69 | "eslint --fix"
70 | ]
71 | },
72 | "husky": {
73 | "hooks": {
74 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
75 | }
76 | },
77 | "pre-commit": "lint-staged"
78 | }
79 |
--------------------------------------------------------------------------------
/test/fixtures/input.js:
--------------------------------------------------------------------------------
1 | console.log('Hello World'); // eslint-disable-line
2 |
--------------------------------------------------------------------------------
/test/fixtures/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | entry: [resolve(__dirname, 'input.js')],
6 | output: {
7 | path: __dirname,
8 | filename: 'output.js'
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const test = require('ava');
4 | const killable = require('killable');
5 | const merge = require('merge-options');
6 | const Koa = require('koa');
7 | const compose = require('koa-compose');
8 | const request = require('supertest');
9 | const webpack = require('webpack');
10 |
11 | const koaWebpack = require('../lib');
12 |
13 | const config = require('./fixtures/webpack.config');
14 |
15 | const defaults = {
16 | config,
17 | devMiddleware: {
18 | publicPath: '/',
19 | logLevel: 'silent'
20 | },
21 | hotClient: {
22 | logLevel: 'silent'
23 | }
24 | };
25 |
26 | function buildOptions(opts) {
27 | const options = merge({}, defaults, opts);
28 | return merge(options, {
29 | config: null,
30 | ...(opts.configPath ? {} : { compiler: webpack(options.config) })
31 | });
32 | }
33 |
34 | function defaultApp(middleware) {
35 | return middleware;
36 | }
37 |
38 | async function setup(opts, setupMiddleware = defaultApp) {
39 | const app = new Koa();
40 | const options = buildOptions(opts);
41 | const middleware = await koaWebpack(options);
42 |
43 | app.use(setupMiddleware(middleware));
44 |
45 | const server = app.listen();
46 | const req = request(server);
47 |
48 | killable(server);
49 |
50 | return { middleware, req, server };
51 | }
52 |
53 | function close(server, middleware) {
54 | return new Promise((r) => server.kill(middleware.close(r)));
55 | }
56 |
57 | test('should provide access to middleware and client', async (t) => {
58 | const { middleware, req, server } = await setup({
59 | devMiddleware: { lazy: false }
60 | });
61 |
62 | await req.get('/output.js');
63 |
64 | const { devMiddleware, hotClient } = middleware;
65 |
66 | t.truthy(devMiddleware);
67 | t.truthy(devMiddleware.close);
68 | t.truthy(hotClient);
69 | t.truthy(hotClient.close);
70 |
71 | return close(server, middleware);
72 | });
73 |
74 | test('should disable hot-client', async (t) => {
75 | const { middleware, req, server } = await setup({
76 | devMiddleware: { lazy: false },
77 | hotClient: false
78 | });
79 |
80 | await req.get('/output.js');
81 |
82 | t.truthy(middleware.devMiddleware);
83 | t.is(middleware.hotClient, null);
84 |
85 | return close(server, middleware);
86 | });
87 |
88 | test('sends the result in watch mode', async (t) => {
89 | const { middleware, req, server } = await setup({
90 | devMiddleware: { lazy: false }
91 | });
92 |
93 | const response = await req.get('/output.js').expect(200);
94 |
95 | t.regex(response.text, /Hello World/);
96 |
97 | return close(server, middleware);
98 | });
99 |
100 | test('sends the result to a MultiCompiler in watch mode', async (t) => {
101 | const { middleware, req, server } = await setup({
102 | devMiddleware: { lazy: false },
103 | config: [
104 | {
105 | entry: [resolve(__dirname, 'fixtures', 'input.js')],
106 | output: {
107 | path: resolve(__dirname, 'fixtures'),
108 | filename: 'output.js'
109 | }
110 | },
111 | {
112 | entry: [resolve(__dirname, 'fixtures', 'input.js')],
113 | output: {
114 | path: resolve(__dirname, 'fixtures'),
115 | filename: 'output2.js'
116 | }
117 | }
118 | ]
119 | });
120 |
121 | let response = await req.get('/output.js').expect(200);
122 |
123 | t.regex(response.text, /Hello World/);
124 |
125 | response = await req.get('/output2.js').expect(200);
126 |
127 | t.regex(response.text, /Hello World/);
128 |
129 | return close(server, middleware);
130 | });
131 |
132 | test('builds and sends the result in lazy mode', async (t) => {
133 | const { middleware, req, server } = await setup({
134 | devMiddleware: { lazy: true }
135 | });
136 |
137 | const response = await req.get('/output.js').expect(200);
138 |
139 | t.regex(response.text, /Hello World/);
140 |
141 | return close(server, middleware);
142 | });
143 |
144 | test('continues on if the file is not part of webpack', async (t) => {
145 | const mware = (webpackMiddleware) =>
146 | compose([
147 | webpackMiddleware,
148 | async (ctx) => {
149 | ctx.body = 'foo'; // eslint-disable-line no-param-reassign
150 | }
151 | ]);
152 |
153 | const { middleware, req, server } = await setup({}, mware);
154 |
155 | const response = await req.get('/some-other-file.js').expect(200);
156 |
157 | t.is(response.text, 'foo');
158 |
159 | return close(server, middleware);
160 | });
161 |
162 | test('uses supplied Webpack configuration file', async (t) => {
163 | const { middleware, req, server } = await setup({
164 | configPath: resolve(__dirname, 'fixtures', 'webpack.config.js')
165 | });
166 |
167 | const response = await req.get('/output.js').expect(200);
168 |
169 | t.regex(response.text, /Hello World/);
170 |
171 | return close(server, middleware);
172 | });
173 |
--------------------------------------------------------------------------------