├── .cspell.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
├── CODEOWNERS
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── BUG.md
│ ├── DOCS.md
│ ├── FEATURE.md
│ ├── MODIFICATION.md
│ └── SUPPORT.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── dependency-review.yml
│ └── nodejs.yml
├── .gitignore
├── .husky
├── .gitignore
├── commit-msg
└── pre-commit
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── commitlint.config.js
├── husky.config.js
├── lint-staged.config.js
├── package-lock.json
├── package.json
├── src
├── cjs.js
├── index.js
└── options.json
└── test
├── __snapshots__
├── loader.test.js.snap
└── validate-options.test.js.snap
├── cjs.test.js
├── fixtures
├── broken.js
├── broken.node
├── example
│ ├── binding.gyp
│ ├── hello.cc
│ ├── package-lock.json
│ └── package.json
├── from-node_modules.js
└── simple.js
├── helpers
├── compile.js
├── execute.js
├── getCompiler.js
├── getErrors.js
├── getModuleSource.js
├── getWarnings.js
├── index.js
├── normalizeErrors.js
├── readAsset.js
└── readAssets.js
├── loader.test.js
└── validate-options.test.js
/.cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2",
3 | "language": "en,en-gb",
4 | "words": [
5 | "commitlint",
6 | "dlopen",
7 | "RTLD",
8 | "Koppers",
9 | "sokra",
10 | "napi",
11 | "NAPI",
12 | "memfs"
13 | ],
14 |
15 | "ignorePaths": [
16 | "CHANGELOG.md",
17 | "package.json",
18 | "dist/**",
19 | "**/__snapshots__/**",
20 | "package-lock.json",
21 | "node_modules",
22 | "coverage",
23 | "*.log"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/.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 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /dist
3 | /node_modules
4 | /test/fixtures
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ["@webpack-contrib/eslint-config-webpack", "prettier"],
4 | };
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | package-lock.json -diff
2 | * text=auto
3 | bin/* eol=lf
4 | yarn.lock -diff
5 |
6 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These are the default owners for everything in
2 | # webpack-contrib
3 | @webpack-contrib/org-maintainers
4 |
5 | # Add repository specific users / groups
6 | # below here for libs that are not maintained by the org.
7 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing in @webpack-contrib
2 |
3 | We'd always love contributions to further improve the webpack / webpack-contrib ecosystem!
4 | Here are the guidelines we'd like you to follow:
5 |
6 | - [Questions and Problems](#question)
7 | - [Issues and Bugs](#issue)
8 | - [Feature Requests](#feature)
9 | - [Pull Request Submission Guidelines](#submit-pr)
10 | - [Commit Message Conventions](#commit)
11 |
12 | ## Got a Question or Problem?
13 |
14 | Please submit support requests and questions to StackOverflow using the tag [[webpack]](http://stackoverflow.com/tags/webpack).
15 | StackOverflow is better suited for this kind of support though you may also inquire in [Webpack Gitter](https://gitter.im/webpack/webpack).
16 | The issue tracker is for bug reports and feature discussions.
17 |
18 | ## Found an Issue or Bug?
19 |
20 | Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
21 |
22 | We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we ask that you to provide a minimal reproduction scenario (github repo or failing test case). Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like:
23 |
24 | - version of Webpack used
25 | - version of the loader / plugin you are creating a bug report for
26 | - the use-case that fails
27 |
28 | A minimal reproduce scenario allows us to quickly confirm a bug (or point out config problems) as well as confirm that we are fixing the right problem.
29 |
30 | We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
31 |
32 | Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced.
33 |
34 | ## Feature Requests?
35 |
36 | You can _request_ a new feature by creating an issue on Github.
37 |
38 | If you would like to _implement_ a new feature, please submit an issue with a proposal for your work `first`, to be sure that particular makes sense for the project.
39 |
40 | ## Pull Request Submission Guidelines
41 |
42 | Before you submit your Pull Request (PR) consider the following guidelines:
43 |
44 | - Search Github for an open or closed PR that relates to your submission. You don't want to duplicate effort.
45 | - Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit). Adherence to these conventions is necessary because release notes are automatically generated from these messages.
46 | - Fill out our `Pull Request Template`. Your pull request will not be considered if it is ignored.
47 | - Please sign the `Contributor License Agreement (CLA)` when a pull request is opened. We cannot accept your pull request without this. Make sure you sign with the primary email address associated with your local / github account.
48 |
49 | ## Webpack Contrib Commit Conventions
50 |
51 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
52 | format that includes a **type**, a **scope** and a **subject**:
53 |
54 | ```
55 | ():
56 |
57 |
58 |
59 |
60 | ```
61 |
62 | The **header** is mandatory and the **scope** of the header is optional.
63 |
64 | Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
65 | to read on GitHub as well as in various git tools.
66 |
67 | The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
68 |
69 | Examples:
70 |
71 | ```
72 | docs(readme): update install instructions
73 | ```
74 |
75 | ```
76 | fix: refer to the `entrypoint` instead of the first `module`
77 | ```
78 |
79 | ### Revert
80 |
81 | If the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit.
82 | In the body it should say: `This reverts commit .`, where the hash is the SHA of the commit being reverted.
83 |
84 | ### Type
85 |
86 | Must be one of the following:
87 |
88 | - **build**: Changes that affect the build system or external dependencies (example scopes: babel, npm)
89 | - **chore**: Changes that fall outside of build / docs that do not effect source code (example scopes: package, defaults)
90 | - **ci**: Changes to our CI configuration files and scripts (example scopes: circleci, travis)
91 | - **docs**: Documentation only changes (example scopes: readme, changelog)
92 | - **feat**: A new feature
93 | - **fix**: A bug fix
94 | - **perf**: A code change that improves performance
95 | - **refactor**: A code change that neither fixes a bug nor adds a feature
96 | - **revert**: Used when reverting a committed change
97 | - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons)
98 | - **test**: Addition of or updates to Jest tests
99 |
100 | ### Scope
101 |
102 | The scope is subjective & depends on the `type` see above. A good example would be a change to a particular class / module.
103 |
104 | ### Subject
105 |
106 | The subject contains a succinct description of the change:
107 |
108 | - use the imperative, present tense: "change" not "changed" nor "changes"
109 | - don't capitalize the first letter
110 | - no dot (.) at the end
111 |
112 | ### Body
113 |
114 | Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
115 | The body should include the motivation for the change and contrast this with previous behavior.
116 |
117 | ### Footer
118 |
119 | The footer should contain any information about **Breaking Changes** and is also the place to
120 | reference GitHub issues that this commit **Closes**.
121 |
122 | **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
123 |
124 | Example
125 |
126 | ```
127 | BREAKING CHANGE: Updates to `Chunk.mapModules`.
128 |
129 | This release is not backwards compatible with `Webpack 2.x` due to breaking changes in webpack/webpack#4764
130 | Migration: see webpack/webpack#5225
131 |
132 | ```
133 |
134 | ## Testing Your Pull Request
135 |
136 | You may have the need to test your changes in a real-world project or dependent
137 | module. Thankfully, Github provides a means to do this. Add a dependency to the
138 | `package.json` for such a project as follows:
139 |
140 | ```json
141 | {
142 | "devDependencies": {
143 | "node-loader": "webpack-contrib/node-loader#{id}/head"
144 | }
145 | }
146 | ```
147 |
148 | Where `{id}` is the # ID of your Pull Request.
149 |
150 | ## Contributor License Agreement
151 |
152 | When submitting your contribution, a CLA (Contributor License Agreement) bot will come by to verify that you signed the [CLA](https://easycla.lfx.linuxfoundation.org/#/?version=2).
153 | If it is your first time, it will link you to the right place to sign it.
154 | However, if you have committed your contributions using an email that is not the same as your email used on GitHub, the CLA bot can't accept your contribution.
155 |
156 | Run `git config user.email` to see your Git email, and verify it with [your GitHub email](https://github.com/settings/emails).
157 |
158 | ## Thanks
159 |
160 | For your interest, time, understanding, and for following this simple guide.
161 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: webpack
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐛 Bug Report
3 | about: Something went awry and you'd like to tell us about it.
4 | ---
5 |
6 |
7 |
8 |
9 | ### Bug report
10 |
11 |
12 |
13 |
14 |
15 |
16 | ### Actual Behavior
17 |
18 |
19 |
20 | ### Expected Behavior
21 |
22 |
23 |
24 |
25 | ### How Do We Reproduce?
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/DOCS.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 📚 Documentation
3 | about: Are the docs lacking or missing something? Do they need some new 🔥 hotness? Tell us here.
4 | ---
5 |
6 |
7 |
8 |
9 | Documentation Is:
10 |
11 |
12 |
13 | - [ ] Missing
14 | - [ ] Needed
15 | - [ ] Confusing
16 | - [ ] Not Sure?
17 |
18 | ### Please Explain in Detail...
19 |
20 |
21 |
22 |
23 |
24 |
25 | ### Your Proposal for Changes
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: ✨ Feature Request
3 | about: Suggest an idea for this project
4 | ---
5 |
6 |
7 |
8 |
9 | ### Feature Proposal
10 |
11 |
12 |
13 |
14 |
15 |
16 | ### Feature Use Case
17 |
18 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/MODIFICATION.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🔧 Modification Request
3 | about: Would you like something work differently? Have an alternative approach? This is the template for you.
4 | ---
5 |
6 |
7 |
8 |
9 | ### Modification Proposal
10 |
11 |
12 |
13 |
14 |
15 |
16 | ### Expected Behavior / Situation
17 |
18 | ### Actual Behavior / Situation
19 |
20 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/SUPPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🆘 Support, Help, and Advice
3 | about: 👉🏽 Need support, help, or advice? Don't open an issue! Head to https://github.com/webpack/webpack/discussions, StackOverflow or https://gitter.im/webpack/webpack.
4 | ---
5 |
6 | Hey there! If you need support, help, or advice then this is not the place to ask.
7 | Please visit [GitHub Discussions](https://github.com/webpack/webpack/discussions) or [StackOverflow](https://stackoverflow.com/questions/tagged/webpack) instead.
8 |
--------------------------------------------------------------------------------
/.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
36 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review.yml:
--------------------------------------------------------------------------------
1 | name: "Dependency Review"
2 | on: [pull_request]
3 |
4 | permissions:
5 | contents: read
6 |
7 | jobs:
8 | dependency-review:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: "Checkout Repository"
12 | uses: actions/checkout@v3
13 | - name: "Dependency Review"
14 | uses: actions/dependency-review-action@v4
15 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | name: node-loader
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - next
8 | pull_request:
9 | branches:
10 | - master
11 | - next
12 |
13 | permissions:
14 | contents: read
15 |
16 | jobs:
17 | lint:
18 | name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }}
19 |
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 |
23 | strategy:
24 | matrix:
25 | os: [ubuntu-latest]
26 | node-version: [lts/*]
27 |
28 | runs-on: ${{ matrix.os }}
29 |
30 | concurrency:
31 | group: lint-${{ matrix.os }}-v${{ matrix.node-version }}-${{ github.ref }}
32 | cancel-in-progress: true
33 |
34 | steps:
35 | - uses: actions/checkout@v4
36 | with:
37 | fetch-depth: 0
38 |
39 | - name: Use Node.js ${{ matrix.node-version }}
40 | uses: actions/setup-node@v4
41 | with:
42 | node-version: ${{ matrix.node-version }}
43 | cache: "npm"
44 |
45 | - name: Install dependencies
46 | run: npm ci
47 |
48 | - name: Lint
49 | run: npm run lint
50 |
51 | - name: Security audit
52 | run: npm run security
53 |
54 | - name: Validate PR commits with commitlint
55 | if: github.event_name == 'pull_request'
56 | run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose
57 |
58 | test:
59 | name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version }}, Webpack ${{ matrix.webpack-version }}
60 |
61 | strategy:
62 | matrix:
63 | os: [ubuntu-latest, windows-latest, macos-latest]
64 | node-version: [10.x, 12.x, 14.x, 16.x, 18.x, 20.x, 22.x]
65 | webpack-version: [latest]
66 | exclude:
67 | - os: windows-latest
68 | node-version: 10.x
69 | - os: macos-latest
70 | node-version: 10.x
71 | - os: macos-latest
72 | node-version: 12.x
73 | - os: macos-latest
74 | node-version: 14.x
75 |
76 | runs-on: ${{ matrix.os }}
77 |
78 | concurrency:
79 | group: test-${{ matrix.os }}-v${{ matrix.node-version }}-${{ matrix.webpack-version }}-${{ github.ref }}
80 | cancel-in-progress: true
81 |
82 | steps:
83 | - name: Setup Git
84 | if: matrix.os == 'windows-latest'
85 | run: git config --global core.autocrlf input
86 |
87 | - uses: actions/checkout@v4
88 |
89 | - name: Use Node.js ${{ matrix.node-version }}
90 | uses: actions/setup-node@v4
91 | with:
92 | node-version: ${{ matrix.node-version }}
93 | cache: "npm"
94 |
95 | - name: Update node-gyp on windows
96 | if: matrix.os == 'windows-latest' && (matrix.node-version == '12.x' || matrix.node-version == '14.x')
97 | run: Get-Command node | Select-Object -ExpandProperty Source | Join-Path -ChildPath "..\node_modules\npm\node_modules\npm-lifecycle" -Resolve | Push-Location; npm install node-gyp@8.x; Pop-Location
98 |
99 | - name: Install Python setuptools on ubuntu
100 | if: matrix.os == 'ubuntu-latest'
101 | run: python3 -m pip install setuptools
102 |
103 | - name: Install Python setuptools on macos
104 | if: matrix.os == 'macos-latest'
105 | run: brew install python-setuptools
106 |
107 | - name: Install Python setuptools on windows
108 | if: matrix.os == 'windows-latest'
109 | run: python -m pip install setuptools
110 |
111 | - name: Install dependencies
112 | run: npm ci
113 |
114 | - name: Install webpack ${{ matrix.webpack-version }}
115 | if: matrix.webpack-version != 'latest'
116 | run: npm i webpack@${{ matrix.webpack-version }}
117 |
118 | - name: Run tests for webpack version ${{ matrix.webpack-version }}
119 | run: npm run test:coverage -- --ci
120 |
121 | - name: Submit coverage data to codecov
122 | uses: codecov/codecov-action@v4
123 | with:
124 | token: ${{ secrets.CODECOV_TOKEN }}
125 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs
2 | *.log
3 | npm-debug.log*
4 | .eslintcache
5 | /coverage
6 | /dist
7 | /local
8 | /reports
9 | /node_modules
10 | .DS_Store
11 | Thumbs.db
12 | .idea
13 | .vscode
14 | *.sublime-project
15 | *.sublime-workspace
16 | *.iml
17 | test/fixtures/example/build
18 | test/fixtures/example/node_modules
19 |
20 |
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx --no-install commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /dist
3 | /node_modules
4 | /test/fixtures
5 | CHANGELOG.md
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
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.
4 |
5 | ## [2.1.0](https://github.com/webpack-contrib/node-loader/compare/v2.0.0...v2.1.0) (2024-11-13)
6 |
7 |
8 | ### Features
9 |
10 | * display helpful description and links on error ([#54](https://github.com/webpack-contrib/node-loader/issues/54)) ([31c0009](https://github.com/webpack-contrib/node-loader/commit/31c00094de7b443e639ffdb15bb33b56365930d2))
11 |
12 |
13 | ### Bug Fixes
14 |
15 | * dlopen relative part problem in mac system ([0507d0b](https://github.com/webpack-contrib/node-loader/commit/0507d0b5b139d1558d9917cb29bfce12d4c1ac26))
16 |
17 | ## [2.0.0](https://github.com/webpack-contrib/node-loader/compare/v1.0.3...v2.0.0) (2021-04-05)
18 |
19 |
20 | ### ⚠ BREAKING CHANGES
21 |
22 | * minimum supported webpack version is `5`
23 |
24 | * dropped webpack@4 ([#33](https://github.com/webpack-contrib/node-loader/issues/33)) ([de9d1a5](https://github.com/webpack-contrib/node-loader/commit/de9d1a5a2ec39868217d03569352811fc0df1a8f))
25 |
26 | ### [1.0.3](https://github.com/webpack-contrib/node-loader/compare/v1.0.2...v1.0.3) (2021-04-05)
27 |
28 |
29 | ### Bug Fixes
30 |
31 | * concat directory separators instead of "/" to make it work on Windows [#39](https://github.com/webpack-contrib/node-loader/issues/39) ([#40](https://github.com/webpack-contrib/node-loader/issues/40)) ([3eb7041](https://github.com/webpack-contrib/node-loader/commit/3eb7041089b2f17b7125aba38670d63166b9a5c9))
32 |
33 | ### [1.0.2](https://github.com/webpack-contrib/node-loader/compare/v1.0.1...v1.0.2) (2020-10-09)
34 |
35 | ### Chore
36 |
37 | * update `schema-utils`
38 |
39 | ### [1.0.1](https://github.com/webpack-contrib/node-loader/compare/v1.0.0...v1.0.1) (2020-07-28)
40 |
41 |
42 | ### Bug Fixes
43 |
44 | * compatibility with `electron` ([#27](https://github.com/webpack-contrib/node-loader/issues/27)) ([9e32a3c](https://github.com/webpack-contrib/node-loader/commit/9e32a3cc46c4d846d0c4b1c76a5b29d60ad83929))
45 |
46 | ### [1.0.0](https://github.com/webpack-contrib/node-loader/compare/v0.6.0...v1.0.0) (2020-06-26)
47 |
48 | ### ⚠ BREAKING CHANGES
49 |
50 | * minimum supported Node.js version is `10.13`
51 | * minimum supported `webpack` version is `4`
52 |
53 | ### Features
54 |
55 | * support webpack 5
56 | * `flags` option ([#20](https://github.com/webpack-contrib/node-loader/issues/20)) ([afc43f8](https://github.com/webpack-contrib/node-loader/commit/afc43f80046402774037a8c0de5e513f2795ffa1))
57 | * `name` option ([#20](https://github.com/webpack-contrib/node-loader/issues/20)) ([afc43f8](https://github.com/webpack-contrib/node-loader/commit/afc43f80046402774037a8c0de5e513f2795ffa1))
58 |
59 | ### Fixes
60 |
61 | * copy `.node` files to the build directory
62 | * do not put absolute paths in the bundle file (no problems with `[contenthash]`)
63 |
64 | # Change Log
65 |
66 | 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.
67 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | 'Software'), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEPRECATED in favor of https://github.com/webpack/webpack/tree/main/examples/nodejs-addons
2 |
3 |
8 |
9 | [![npm][npm]][npm-url]
10 | [![node][node]][node-url]
11 | [![tests][tests]][tests-url]
12 | [![coverage][cover]][cover-url]
13 | [![discussion][discussion]][discussion-url]
14 | [![size][size]][size-url]
15 |
16 | # node-loader
17 |
18 | A [Node.js add-ons](https://nodejs.org/dist/latest/docs/api/addons.html) loader.
19 |
20 | Allows to connect native node modules with `.node` extension.
21 |
22 | > ⚠ `node-loader` only works on the `node`/`async-node`/`electron-main`/`electron-renderer`/`electron-preload` targets.
23 |
24 | ## Getting Started
25 |
26 | To begin, you'll need to install `node-loader`:
27 |
28 | ```console
29 | npm install node-loader --save-dev
30 | ```
31 |
32 | or
33 |
34 | ```console
35 | yarn add -D node-loader
36 | ```
37 |
38 | or
39 |
40 | ```console
41 | pnpm add -D node-loader
42 | ```
43 |
44 | Setup the `target` option to `node`/`async-node`/`electron-main`/`electron-renderer`/`electron-preload` value and do not mock the `__dirname` global variable.
45 |
46 | **webpack.config.js**
47 |
48 | ```js
49 | module.exports = {
50 | resolve: {
51 | extensions: ["...", ".node"],
52 | },
53 | target: "node",
54 | node: {
55 | __dirname: false,
56 | },
57 | module: {
58 | rules: [
59 | {
60 | test: /\.node$/,
61 | loader: "node-loader",
62 | },
63 | ],
64 | },
65 | };
66 | ```
67 |
68 | ### Inline
69 |
70 | **index.js**
71 |
72 | ```js
73 | import node from "node-loader!./file.node";
74 | ```
75 |
76 | And run `webpack` via your preferred method.
77 |
78 | ### Configuration
79 |
80 | **index.js**
81 |
82 | ```js
83 | import node from "file.node";
84 | ```
85 |
86 | Then add the loader to your `webpack` config. For example:
87 |
88 | **webpack.config.js**
89 |
90 | ```js
91 | module.exports = {
92 | target: "node",
93 | node: {
94 | __dirname: false,
95 | },
96 | module: {
97 | rules: [
98 | {
99 | test: /\.node$/,
100 | loader: "node-loader",
101 | },
102 | ],
103 | },
104 | };
105 | ```
106 |
107 | And run `webpack` via your preferred method.
108 |
109 | ## Options
110 |
111 | | Name | Type | Default | Description |
112 | | :-------------------: | :------------------: | :---------------------: | :----------------------------------------------------------- |
113 | | **[`flags`](#flags)** | `{Number}` | `undefined` | Enables/Disables `url`/`image-set` functions handling |
114 | | **[`name`](#name)** | `{String\|Function}` | `'[contenthash].[ext]'` | Specifies a custom filename template for the target file(s). |
115 |
116 | ### `flags`
117 |
118 | Type: `Number`
119 | Default: `undefined`
120 |
121 | The `flags` argument is an integer that allows to specify dlopen behavior.
122 | See the [`process.dlopen`](https://nodejs.org/api/process.html#process_process_dlopen_module_filename_flags) documentation for details.
123 |
124 | **index.js**
125 |
126 | ```js
127 | import node from "file.node";
128 | ```
129 |
130 | **webpack.config.js**
131 |
132 | ```js
133 | const os = require("os");
134 |
135 | module.exports = {
136 | target: "node",
137 | node: {
138 | __dirname: false,
139 | },
140 | module: {
141 | rules: [
142 | {
143 | test: /\.node$/,
144 | loader: "node-loader",
145 | options: {
146 | flags: os.constants.dlopen.RTLD_NOW,
147 | },
148 | },
149 | ],
150 | },
151 | };
152 | ```
153 |
154 | ### `name`
155 |
156 | Type: `String|Function`
157 | Default: `'[contenthash].[ext]'`
158 |
159 | Specifies a custom filename template for the target file(s).
160 |
161 | #### `String`
162 |
163 | **webpack.config.js**
164 |
165 | ```js
166 | module.exports = {
167 | target: "node",
168 | node: {
169 | __dirname: false,
170 | },
171 | module: {
172 | rules: [
173 | {
174 | test: /\.node$/,
175 | loader: "node-loader",
176 | options: {
177 | name: "[path][name].[ext]",
178 | },
179 | },
180 | ],
181 | },
182 | };
183 | ```
184 |
185 | #### `Function`
186 |
187 | **webpack.config.js**
188 |
189 | ```js
190 | module.exports = {
191 | target: "node",
192 | node: {
193 | __dirname: false,
194 | },
195 | module: {
196 | rules: [
197 | {
198 | test: /\.node$/,
199 | loader: "node-loader",
200 | options: {
201 | name(resourcePath, resourceQuery) {
202 | // `resourcePath` - `/absolute/path/to/file.js`
203 | // `resourceQuery` - `?foo=bar`
204 |
205 | if (process.env.NODE_ENV === "development") {
206 | return "[path][name].[ext]";
207 | }
208 |
209 | return "[contenthash].[ext]";
210 | },
211 | },
212 | },
213 | ],
214 | },
215 | };
216 | ```
217 |
218 | ## Contributing
219 |
220 | Please take a moment to read our contributing guidelines if you haven't yet done so.
221 |
222 | [CONTRIBUTING](./.github/CONTRIBUTING.md)
223 |
224 | ## License
225 |
226 | [MIT](./LICENSE)
227 |
228 | [npm]: https://img.shields.io/npm/v/node-loader.svg
229 | [npm-url]: https://npmjs.com/package/node-loader
230 | [node]: https://img.shields.io/node/v/node-loader.svg
231 | [node-url]: https://nodejs.org
232 | [tests]: https://github.com/webpack-contrib/node-loader/workflows/node-loader/badge.svg
233 | [tests-url]: https://github.com/webpack-contrib/node-loader/actions
234 | [cover]: https://codecov.io/gh/webpack-contrib/node-loader/branch/master/graph/badge.svg
235 | [cover-url]: https://codecov.io/gh/webpack-contrib/node-loader
236 | [discussion]: https://img.shields.io/github/discussions/webpack/webpack
237 | [discussion-url]: https://github.com/webpack/webpack/discussions
238 | [size]: https://packagephobia.now.sh/badge?p=node-loader
239 | [size-url]: https://packagephobia.now.sh/result?p=node-loader
240 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | const MIN_BABEL_VERSION = 7;
2 |
3 | module.exports = (api) => {
4 | api.assertVersion(MIN_BABEL_VERSION);
5 | api.cache(true);
6 |
7 | return {
8 | presets: [
9 | [
10 | "@babel/preset-env",
11 | {
12 | targets: {
13 | node: "10.13.0",
14 | },
15 | },
16 | ],
17 | ],
18 | };
19 | };
20 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["@commitlint/config-conventional"],
3 | rules: {
4 | "header-max-length": [0],
5 | "body-max-line-length": [0],
6 | "footer-max-line-length": [0],
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/husky.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | hooks: {
3 | "pre-commit": "lint-staged",
4 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/lint-staged.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "*.js": ["prettier --write", "eslint --fix", "cspell"],
3 | "*.{json,md,yml,css,ts}": ["prettier --write"],
4 | };
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-loader",
3 | "version": "2.1.0",
4 | "description": "A Node loader module for enhanced-require",
5 | "license": "MIT",
6 | "repository": "webpack-contrib/node-loader",
7 | "author": "Tobias Koppers @sokra",
8 | "homepage": "https://github.com/webpack-contrib/node-loader",
9 | "bugs": "https://github.com/webpack-contrib/node-loader/issues",
10 | "funding": {
11 | "type": "opencollective",
12 | "url": "https://opencollective.com/webpack"
13 | },
14 | "main": "dist/cjs.js",
15 | "engines": {
16 | "node": ">= 10.13.0"
17 | },
18 | "scripts": {
19 | "start": "npm run build -- -w",
20 | "clean": "del-cli dist",
21 | "prebuild": "npm run clean",
22 | "build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
23 | "commitlint": "commitlint --from=master",
24 | "security": "npm audit --production",
25 | "lint:prettier": "prettier --list-different .",
26 | "lint:js": "eslint --cache .",
27 | "lint:spelling": "cspell \"**/*.*\"",
28 | "lint": "npm-run-all -l -p \"lint:**\"",
29 | "fix:js": "npm run lint:js -- --fix",
30 | "fix:prettier": "npm run lint:prettier -- --write",
31 | "fix": "npm-run-all -l fix:js fix:prettier",
32 | "pretest:only": "cd test/fixtures/example && npm i",
33 | "test:only": "cross-env NODE_ENV=test jest",
34 | "test:watch": "npm run test:only -- --watch",
35 | "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
36 | "pretest": "npm run lint",
37 | "test": "npm run test:coverage",
38 | "prepare": "husky install && npm run build",
39 | "release": "standard-version"
40 | },
41 | "files": [
42 | "dist"
43 | ],
44 | "peerDependencies": {
45 | "webpack": "^5.0.0"
46 | },
47 | "dependencies": {
48 | "loader-utils": "^2.0.3"
49 | },
50 | "devDependencies": {
51 | "@babel/cli": "^7.21.5",
52 | "@babel/core": "^7.22.1",
53 | "@babel/preset-env": "^7.22.4",
54 | "@commitlint/cli": "^12.1.4",
55 | "@commitlint/config-conventional": "^12.1.4",
56 | "@webpack-contrib/eslint-config-webpack": "^3.0.0",
57 | "babel-jest": "^27.5.1",
58 | "cross-env": "^7.0.3",
59 | "cspell": "^6.31.1",
60 | "del": "^6.1.1",
61 | "del-cli": "^3.0.1",
62 | "eslint": "^7.32.0",
63 | "eslint-config-prettier": "^8.8.0",
64 | "eslint-plugin-import": "^2.27.5",
65 | "husky": "^6.0.0",
66 | "jest": "^27.5.1",
67 | "lint-staged": "^10.5.4",
68 | "memfs": "^3.5.1",
69 | "npm-run-all": "^4.1.5",
70 | "prettier": "^2.8.8",
71 | "standard-version": "^9.5.0",
72 | "webpack": "^5.85.0"
73 | },
74 | "keywords": [
75 | "webpack"
76 | ]
77 | }
78 |
--------------------------------------------------------------------------------
/src/cjs.js:
--------------------------------------------------------------------------------
1 | const loader = require("./index");
2 |
3 | module.exports = loader.default;
4 | module.exports.raw = loader.raw;
5 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License http://www.opensource.org/licenses/mit-license.php
3 | Author Tobias Koppers @sokra
4 | */
5 |
6 | import { interpolateName } from "loader-utils";
7 |
8 | import schema from "./options.json";
9 |
10 | export default function loader(content) {
11 | const options = this.getOptions(schema);
12 |
13 | const name = interpolateName(
14 | this,
15 | typeof options.name !== "undefined" ? options.name : "[contenthash].[ext]",
16 | {
17 | context: this.rootContext,
18 | content,
19 | }
20 | );
21 |
22 | this.emitFile(name, content);
23 |
24 | return `
25 | try {
26 | process.dlopen(module, require("path").join(__dirname, __webpack_public_path__, ${JSON.stringify(
27 | name
28 | )})${
29 | typeof options.flags !== "undefined"
30 | ? `, ${JSON.stringify(options.flags)}`
31 | : ""
32 | });
33 | } catch (error) {
34 | throw new Error('node-loader:\\n' + error);
35 | }
36 | `;
37 | }
38 |
39 | export const raw = true;
40 |
--------------------------------------------------------------------------------
/src/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Node Loader options",
3 | "type": "object",
4 | "properties": {
5 | "name": {
6 | "anyOf": [
7 | {
8 | "type": "string"
9 | },
10 | {
11 | "instanceof": "Function"
12 | }
13 | ],
14 | "description": "Specifies a custom filename template for the target file(s).",
15 | "link": "https://github.com/webpack-contrib/node-loader#name"
16 | },
17 | "flags": {
18 | "type": "integer",
19 | "description": "An integer value that allows to specify dlopen behavior.",
20 | "link": "https://github.com/webpack-contrib/node-loader#flags"
21 | }
22 | },
23 | "additionalProperties": false
24 | }
25 |
--------------------------------------------------------------------------------
/test/__snapshots__/loader.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`loader should throw an error on broken "node" addon: errors 1`] = `Array []`;
4 |
5 | exports[`loader should throw an error on broken "node" addon: module 1`] = `
6 | "
7 | try {
8 | process.dlopen(module, require(\\"path\\").join(__dirname, __webpack_public_path__, \\"broken.node\\"));
9 | } catch (error) {
10 | throw new Error('node-loader:\\\\n' + error);
11 | }
12 | "
13 | `;
14 |
15 | exports[`loader should throw an error on broken "node" addon: warnings 1`] = `Array []`;
16 |
17 | exports[`loader should work: errors 1`] = `Array []`;
18 |
19 | exports[`loader should work: module 1`] = `
20 | "
21 | try {
22 | process.dlopen(module, require(\\"path\\").join(__dirname, __webpack_public_path__, \\"hello.node\\"), 1);
23 | } catch (error) {
24 | throw new Error('node-loader:\\\\n' + error);
25 | }
26 | "
27 | `;
28 |
29 | exports[`loader should work: result 1`] = `
30 | Object {
31 | "default": "world",
32 | }
33 | `;
34 |
35 | exports[`loader should work: warnings 1`] = `Array []`;
36 |
--------------------------------------------------------------------------------
/test/__snapshots__/validate-options.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`validate options should throw an error on the "flags" option with "false" value 1`] = `
4 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
5 | - options.flags should be an integer.
6 | -> An integer value that allows to specify dlopen behavior.
7 | -> Read more at https://github.com/webpack-contrib/node-loader#flags"
8 | `;
9 |
10 | exports[`validate options should throw an error on the "flags" option with "test" value 1`] = `
11 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
12 | - options.flags should be an integer.
13 | -> An integer value that allows to specify dlopen behavior.
14 | -> Read more at https://github.com/webpack-contrib/node-loader#flags"
15 | `;
16 |
17 | exports[`validate options should throw an error on the "flags" option with "true" value 1`] = `
18 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
19 | - options.flags should be an integer.
20 | -> An integer value that allows to specify dlopen behavior.
21 | -> Read more at https://github.com/webpack-contrib/node-loader#flags"
22 | `;
23 |
24 | exports[`validate options should throw an error on the "name" option with "false" value 1`] = `
25 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
26 | - options.name should be one of these:
27 | string | function
28 | -> Specifies a custom filename template for the target file(s).
29 | -> Read more at https://github.com/webpack-contrib/node-loader#name
30 | Details:
31 | * options.name should be a string.
32 | * options.name should be an instance of function."
33 | `;
34 |
35 | exports[`validate options should throw an error on the "name" option with "true" value 1`] = `
36 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
37 | - options.name should be one of these:
38 | string | function
39 | -> Specifies a custom filename template for the target file(s).
40 | -> Read more at https://github.com/webpack-contrib/node-loader#name
41 | Details:
42 | * options.name should be a string.
43 | * options.name should be an instance of function."
44 | `;
45 |
46 | exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
47 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
48 | - options has an unknown property 'unknown'. These properties are valid:
49 | object { name?, flags? }"
50 | `;
51 |
52 | exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
53 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
54 | - options has an unknown property 'unknown'. These properties are valid:
55 | object { name?, flags? }"
56 | `;
57 |
58 | exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
59 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
60 | - options has an unknown property 'unknown'. These properties are valid:
61 | object { name?, flags? }"
62 | `;
63 |
64 | exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
65 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
66 | - options has an unknown property 'unknown'. These properties are valid:
67 | object { name?, flags? }"
68 | `;
69 |
70 | exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
71 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
72 | - options has an unknown property 'unknown'. These properties are valid:
73 | object { name?, flags? }"
74 | `;
75 |
76 | exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
77 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
78 | - options has an unknown property 'unknown'. These properties are valid:
79 | object { name?, flags? }"
80 | `;
81 |
82 | exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
83 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
84 | - options has an unknown property 'unknown'. These properties are valid:
85 | object { name?, flags? }"
86 | `;
87 |
88 | exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = `
89 | "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema.
90 | - options has an unknown property 'unknown'. These properties are valid:
91 | object { name?, flags? }"
92 | `;
93 |
--------------------------------------------------------------------------------
/test/cjs.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment node
3 | */
4 |
5 | import src from "../src";
6 | import cjs from "../src/cjs";
7 |
8 | describe("cjs", () => {
9 | it("should exported", () => {
10 | expect(cjs).toEqual(src);
11 | });
12 |
13 | it('should export "raw" flag', () => {
14 | expect(cjs.raw).toEqual(true);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/test/fixtures/broken.js:
--------------------------------------------------------------------------------
1 | import foo from './broken.node';
2 |
3 | export default foo;
4 |
--------------------------------------------------------------------------------
/test/fixtures/broken.node:
--------------------------------------------------------------------------------
1 | broken!!!
2 |
--------------------------------------------------------------------------------
/test/fixtures/example/binding.gyp:
--------------------------------------------------------------------------------
1 | {
2 | "targets": [
3 | {
4 | "target_name": "hello",
5 | "sources": [ "hello.cc" ]
6 | }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/test/fixtures/example/hello.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | napi_value Method(napi_env env, napi_callback_info info) {
5 | napi_status status;
6 | napi_value world;
7 | status = napi_create_string_utf8(env, "world", 5, &world);
8 | assert(status == napi_ok);
9 | return world;
10 | }
11 |
12 | #define DECLARE_NAPI_METHOD(name, func) \
13 | { name, 0, func, 0, 0, 0, napi_default, 0 }
14 |
15 | napi_value Init(napi_env env, napi_value exports) {
16 | napi_status status;
17 | napi_property_descriptor desc = DECLARE_NAPI_METHOD("hello", Method);
18 | status = napi_define_properties(env, exports, 1, &desc);
19 | assert(status == napi_ok);
20 | return exports;
21 | }
22 |
23 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
24 |
--------------------------------------------------------------------------------
/test/fixtures/example/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello_world",
3 | "version": "0.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "hello_world",
9 | "version": "0.0.0",
10 | "dependencies": {
11 | "bindings": "^1.5.0"
12 | }
13 | },
14 | "node_modules/bindings": {
15 | "version": "1.5.0",
16 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
17 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
18 | "dependencies": {
19 | "file-uri-to-path": "1.0.0"
20 | }
21 | },
22 | "node_modules/file-uri-to-path": {
23 | "version": "1.0.0",
24 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
25 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
26 | }
27 | },
28 | "dependencies": {
29 | "bindings": {
30 | "version": "1.5.0",
31 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
32 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
33 | "requires": {
34 | "file-uri-to-path": "1.0.0"
35 | }
36 | },
37 | "file-uri-to-path": {
38 | "version": "1.0.0",
39 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
40 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test/fixtures/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello_world",
3 | "version": "0.0.0",
4 | "description": "Node.js Addons Example #1",
5 | "main": "hello.js",
6 | "private": true,
7 | "dependencies": {
8 | "bindings": "^1.5.0"
9 | },
10 | "scripts": {
11 | "test": "node hello.js"
12 | },
13 | "gypfile": true
14 | }
15 |
--------------------------------------------------------------------------------
/test/fixtures/from-node_modules.js:
--------------------------------------------------------------------------------
1 | import foo from 'package';
2 |
3 | export default foo;
4 |
--------------------------------------------------------------------------------
/test/fixtures/simple.js:
--------------------------------------------------------------------------------
1 | import foo from './example/build/Release/hello.node';
2 |
3 | const value = foo.hello();
4 |
5 | export default value;
6 |
--------------------------------------------------------------------------------
/test/helpers/compile.js:
--------------------------------------------------------------------------------
1 | export default (compiler) =>
2 | new Promise((resolve, reject) => {
3 | compiler.run((error, stats) => {
4 | if (error) {
5 | return reject(error);
6 | }
7 |
8 | return resolve(stats);
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/helpers/execute.js:
--------------------------------------------------------------------------------
1 | import Module from "module";
2 | import path from "path";
3 |
4 | const parentModule = module;
5 |
6 | export default (code, dirname) => {
7 | const resource = "test.js";
8 | const module = new Module(resource, parentModule);
9 | // eslint-disable-next-line no-underscore-dangle
10 | module.paths = Module._nodeModulePaths(
11 | path.resolve(__dirname, "../fixtures")
12 | );
13 | module.filename = resource;
14 |
15 | if (!dirname) {
16 | // eslint-disable-next-line no-param-reassign
17 | dirname = path.resolve(__dirname, "../fixtures/example/build/Release");
18 | }
19 |
20 | // eslint-disable-next-line no-underscore-dangle
21 | module._compile(`__dirname = ${JSON.stringify(dirname)};${code};`, resource);
22 |
23 | return module.exports;
24 | };
25 |
--------------------------------------------------------------------------------
/test/helpers/getCompiler.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | import webpack from "webpack";
4 | import { createFsFromVolume, Volume } from "memfs";
5 |
6 | export default (fixture, loaderOptions = {}, config = {}) => {
7 | const fullConfig = {
8 | mode: "development",
9 | devtool: config.devtool || false,
10 | context: path.resolve(__dirname, "../fixtures"),
11 | entry: path.resolve(__dirname, "../fixtures", fixture),
12 | output: {
13 | path: path.resolve(__dirname, "../outputs"),
14 | filename: "[name].bundle.js",
15 | chunkFilename: "[name].chunk.js",
16 | libraryTarget: "commonjs",
17 | },
18 | target: "node",
19 | node: {
20 | __dirname: false,
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.node$/i,
26 | rules: [
27 | {
28 | loader: path.resolve(__dirname, "../../src"),
29 | options: loaderOptions || {},
30 | },
31 | ],
32 | },
33 | ],
34 | },
35 | plugins: [],
36 | ...config,
37 | };
38 |
39 | const compiler = webpack(fullConfig);
40 |
41 | if (!config.outputFileSystem) {
42 | compiler.outputFileSystem = createFsFromVolume(new Volume());
43 | }
44 |
45 | return compiler;
46 | };
47 |
--------------------------------------------------------------------------------
/test/helpers/getErrors.js:
--------------------------------------------------------------------------------
1 | import normalizeErrors from "./normalizeErrors";
2 |
3 | export default (stats) => normalizeErrors(stats.compilation.errors);
4 |
--------------------------------------------------------------------------------
/test/helpers/getModuleSource.js:
--------------------------------------------------------------------------------
1 | export default (name, stats) => {
2 | const { modules } = stats.toJson({ source: true });
3 | const module = modules.find((m) => m.name === name);
4 |
5 | return module.source;
6 | };
7 |
--------------------------------------------------------------------------------
/test/helpers/getWarnings.js:
--------------------------------------------------------------------------------
1 | import normalizeErrors from "./normalizeErrors";
2 |
3 | export default (stats) => normalizeErrors(stats.compilation.warnings);
4 |
--------------------------------------------------------------------------------
/test/helpers/index.js:
--------------------------------------------------------------------------------
1 | import compile from "./compile";
2 | import execute from "./execute";
3 | import getCompiler from "./getCompiler";
4 | import getErrors from "./getErrors";
5 | import getModuleSource from "./getModuleSource";
6 | import getWarnings from "./getWarnings";
7 | import normalizeErrors from "./normalizeErrors";
8 | import readAsset from "./readAsset";
9 | import readsAssets from "./readAssets";
10 |
11 | export {
12 | compile,
13 | execute,
14 | getCompiler,
15 | getErrors,
16 | getModuleSource,
17 | getWarnings,
18 | normalizeErrors,
19 | readAsset,
20 | readsAssets,
21 | };
22 |
--------------------------------------------------------------------------------
/test/helpers/normalizeErrors.js:
--------------------------------------------------------------------------------
1 | function removeCWD(str) {
2 | const isWin = process.platform === "win32";
3 | let cwd = process.cwd();
4 |
5 | if (isWin) {
6 | // eslint-disable-next-line no-param-reassign
7 | str = str.replace(/\\/g, "/");
8 | // eslint-disable-next-line no-param-reassign
9 | cwd = cwd.replace(/\\/g, "/");
10 | }
11 |
12 | return str.replace(new RegExp(cwd, "g"), "");
13 | }
14 |
15 | export default (errors) =>
16 | errors.map((error) =>
17 | removeCWD(error.toString().split("\n").slice(0, 2).join("\n"))
18 | );
19 |
--------------------------------------------------------------------------------
/test/helpers/readAsset.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | export default (asset, compiler, stats) => {
4 | const usedFs = compiler.outputFileSystem;
5 | const outputPath = stats.compilation.outputOptions.path;
6 |
7 | let data = "";
8 | let targetFile = asset;
9 |
10 | const queryStringIdx = targetFile.indexOf("?");
11 |
12 | if (queryStringIdx >= 0) {
13 | targetFile = targetFile.slice(0, queryStringIdx);
14 | }
15 |
16 | try {
17 | data = usedFs.readFileSync(path.join(outputPath, targetFile)).toString();
18 | } catch (error) {
19 | data = error.toString();
20 | }
21 |
22 | return data;
23 | };
24 |
--------------------------------------------------------------------------------
/test/helpers/readAssets.js:
--------------------------------------------------------------------------------
1 | import readAsset from "./readAsset";
2 |
3 | export default function readAssets(compiler, stats) {
4 | const assets = {};
5 |
6 | Object.keys(stats.compilation.assets).forEach((asset) => {
7 | assets[asset] = readAsset(asset, compiler, stats);
8 | });
9 |
10 | return assets;
11 | }
12 |
--------------------------------------------------------------------------------
/test/loader.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment node
3 | */
4 | import {
5 | compile,
6 | execute,
7 | getCompiler,
8 | getErrors,
9 | getModuleSource,
10 | getWarnings,
11 | readAsset,
12 | } from "./helpers";
13 |
14 | describe("loader", () => {
15 | it("should work", async () => {
16 | const compiler = getCompiler("simple.js", {
17 | name: "[name].[ext]",
18 | flags: 1,
19 | });
20 | const stats = await compile(compiler);
21 |
22 | expect(
23 | getModuleSource("./example/build/Release/hello.node", stats)
24 | ).toMatchSnapshot("module");
25 | expect(
26 | execute(readAsset("main.bundle.js", compiler, stats))
27 | ).toMatchSnapshot("result");
28 | expect(getErrors(stats)).toMatchSnapshot("errors");
29 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
30 | });
31 |
32 | it('should throw an error on broken "node" addon', async () => {
33 | const compiler = getCompiler("broken.js", {
34 | name: "[name].[ext]",
35 | });
36 | const stats = await compile(compiler);
37 |
38 | expect(getModuleSource("./broken.node", stats)).toMatchSnapshot("module");
39 |
40 | let error;
41 |
42 | try {
43 | execute(readAsset("main.bundle.js", compiler, stats));
44 | } catch (nodeLoaderError) {
45 | error = nodeLoaderError.message
46 | .replace(new RegExp(process.cwd(), "g"), "/absolute/path/to")
47 | .replace(/\\/g, "/");
48 | }
49 |
50 | expect(error).toBeDefined();
51 | expect(getErrors(stats)).toMatchSnapshot("errors");
52 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/test/validate-options.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment node
3 | */
4 |
5 | import path from "path";
6 | import os from "os";
7 |
8 | import { getCompiler, compile } from "./helpers";
9 |
10 | describe("validate options", () => {
11 | const tests = {
12 | name: {
13 | success: ["[name].[ext]", (resourcePath) => path.basename(resourcePath)],
14 | failure: [true, false],
15 | },
16 | flags: {
17 | success: [os.constants.dlopen.RTLD_NOW],
18 | failure: [true, false, "test"],
19 | },
20 | unknown: {
21 | success: [],
22 | failure: [1, true, false, "test", /test/, [], {}, { foo: "bar" }],
23 | },
24 | };
25 |
26 | function stringifyValue(value) {
27 | if (
28 | Array.isArray(value) ||
29 | (value && typeof value === "object" && value.constructor === Object)
30 | ) {
31 | return JSON.stringify(value);
32 | }
33 |
34 | return value;
35 | }
36 |
37 | async function createTestCase(key, value, type) {
38 | it(`should ${
39 | type === "success" ? "successfully validate" : "throw an error on"
40 | } the "${key}" option with "${stringifyValue(value)}" value`, async () => {
41 | const compiler = getCompiler("simple.js", { [key]: value });
42 |
43 | let stats;
44 |
45 | try {
46 | stats = await compile(compiler);
47 | } finally {
48 | if (type === "success") {
49 | expect(stats.hasErrors()).toBe(false);
50 | } else if (type === "failure") {
51 | const {
52 | compilation: { errors },
53 | } = stats;
54 |
55 | expect(errors).toHaveLength(1);
56 | expect(() => {
57 | throw new Error(errors[0].error.message);
58 | }).toThrowErrorMatchingSnapshot();
59 | }
60 | }
61 | });
62 | }
63 |
64 | for (const [key, values] of Object.entries(tests)) {
65 | for (const type of Object.keys(values)) {
66 | for (const value of values[type]) {
67 | createTestCase(key, value, type);
68 | }
69 | }
70 | }
71 | });
72 |
--------------------------------------------------------------------------------