Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use mocker-api in commonjs with type-checking enabled #125

Open
ikatyang opened this issue Aug 13, 2020 · 8 comments
Open

Unable to use mocker-api in commonjs with type-checking enabled #125

ikatyang opened this issue Aug 13, 2020 · 8 comments

Comments

@ikatyang
Copy link

Version: 2.3.0

Steps to reproduce:

  • execution passed, but type-checking failed

    mkdir mocker-api-repro-execution-passed-but-type-checking-failed
    cd mocker-api-repro-execution-passed-but-type-checking-failed
    npm init -y
    npm install typescript mocker-api
    echo '{"compilerOptions":{"allowJs":true,"checkJs":true,"allowSyntheticDefaultImports":true}}' > tsconfig.json
    echo 'const mockerApi = require("mocker-api"); mockerApi(null, null); console.log("execution passed")' > index.js
    npx tsc --noEmit
    node index.js
    index.js:1:42 - error TS2349: This expression is not callable.
        Type 'typeof import("~/mocker-api-repro-execution-passed-but-type-checking-failed/node_modules/mocker-api/lib/index")' has no call signatures.
    
        1 const mockerApi = require("mocker-api"); mockerApi(null, null); console.log("execution passed")
                                                   ~~~~~~~~~
    
    Found 1 error.
    
    execution passed
  • type-checking passed, but execution failed

    mkdir mocker-api-repro-type-checking-passed-but-execution-failed
    cd mocker-api-repro-type-checking-passed-but-execution-failed
    npm init -y
    npm install typescript mocker-api
    echo '{"compilerOptions":{"allowJs":true,"checkJs":true,"allowSyntheticDefaultImports":true}}' > tsconfig.json
    echo 'const mockerApi = require("mocker-api").default; mockerApi(null, null); console.log("execution passed")' > index.js
    npx tsc --noEmit
    node index.js
    ~/mocker-api-repro-type-checking-passed-but-execution-failed/index.js:1
    const mockerApi = require("mocker-api").default; mockerApi(null, null); console.log("execution passed")
                                                     ^
    
    TypeError: mockerApi is not a function
        at Object.<anonymous> (~/mocker-api-repro-type-checking-passed-but-execution-failed/index.js:1:50)
@jaywcjlove
Copy link
Owner

@ikatyang
Copy link
Author

Sorry, I did not describe the context well. I'm using mocker-api in webpack.config.js, which must be written in commonjs and cannot use import declarations.

@jaywcjlove
Copy link
Owner

@ikatyang Can you give an example of your project?

@ikatyang
Copy link
Author

ikatyang commented Aug 13, 2020

Here are the steps to reproduce the example project:

mkdir repro
cd repro
echo '{
  "name": "mocker-api-repro",
  "version": "1.0.0",
  "main": "src/index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "check": "tsc"
  },
  "dependencies": {
    "axios": "^0.19.2"
  },
  "devDependencies": {
    "@types/webpack": "^4.41.21",
    "@types/webpack-dev-server": "^3.11.0",
    "html-webpack-plugin": "^4.3.0",
    "mocker-api": "^2.3.0",
    "typescript": "^3.9.7",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "engines": {
    "node": "12.x"
  }
}' > package.json
echo '{
  "files": ["src/index.js"],
  "include": ["src/**/*", "mocker/**/*", "*.js"],
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "strict": true,
    "allowJs": true,
    "checkJs": true,
    "allowSyntheticDefaultImports": true,
    "noEmit": true
  }
}' > tsconfig.json
mkdir src
echo '
const axios = require("axios").default;

axios.get("/value").then((res) => {
  document.write(res.data.value);
});
' > src/index.js
echo '
const mockerApi = require("mocker-api");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = /** @type {import("webpack").Configuration} */ ({
  output: {
    publicPath: "/",
  },
  plugins: [new HtmlWebpackPlugin()],
  devServer: {
    host: "0.0.0.0",
    before(app) {
      mockerApi(app, path.join(__dirname, "mocker"));
    },
  },
});
' > webpack.config.js
mkdir mocker
echo '
module.exports = /** @type {import("mocker-api").MockerProxyRoute} */ ({
  "GET /value"(req, res) {
    res.json({ value: "123" });
  },
});
' > mocker/index.js
npm install
npm run check
npm run start
$ npm run check
> tsc

node_modules/mocker-api/lib/index.d.ts:36:5 - error TS2411: Property '_proxy' of type 'MockerOption | undefined' is not assignable to string index type 'MockerResult'.

36     _proxy?: MockerOption;
       ~~~~~~

webpack.config.js:13:7 - error TS2349: This expression is not callable.
  Type 'typeof import("~/mocker-api-repro/node_modules/mocker-api/lib/index")' has no call signatures.

13       mockerApi(app, path.join(__dirname, "mocker"));
         ~~~~~~~~~


Found 2 errors.

@jaywcjlove
Copy link
Owner

😓

@ikatyang
Copy link
Author

Here's the patch I used to workaround this issue, the default export is somehow hidden by the module.exports export:

diff --git a/lib/index.js b/lib/index.js
index 9c66fafbf1e9829d1848259a82f974f43a8d5262..727b2e4a121898dec54ddb00b624211bd9e564f2 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -323,5 +323,4 @@ function _default(app, watchFile) {
   };
 }
 
-module.exports = exports.default; 
 //# sourceMappingURL=index.js.map
\ No newline at end of file

This way I can use const mockerApi = require("mocker-api").default without issues.

@jaywcjlove
Copy link
Owner

jaywcjlove commented Aug 13, 2020

@ikatyang We have used it in many projects. Can't handle it.

const apiMocker = require('mocker-api');
const app = express();
apiMocker(app, require.resolve('./mocker/index'))

- const mockerApi = require("mocker-api").default
+ const mockerApi = require("mocker-api")

@ikatyang
Copy link
Author

Yeah, the better workaround would probably be supporting both default export and module.exports export, for example:

diff --git a/lib/index.js b/lib/index.js
index 9c66fafbf1e9829d1848259a82f974f43a8d5262..d3867d67003185a9d8987a6574f1c7b963322912 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -4,10 +4,6 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild

 var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = _default;

 var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));

@@ -323,5 +319,6 @@ function _default(app, watchFile) {
   };
 }

-module.exports = exports.default;
+module.exports = _default;
+module.exports.default = _default;
 //# sourceMappingURL=index.js.map
\ No newline at end of file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants