admin管理员组

文章数量:1415664

I recently converted my build process over to using typescript and webpack. Now after resolving most the TS errors, I'm trying to run my site finally.

When I load the site, I'm getting TypeError: res.send is not a function from my expressjs static server. This code hasn't changed, it's always been the same even when I used gulp and worked fine but for some reason now after using webpack and TS, it's giving me this error now.

The server does indeed start on port 8080 and listens for requests. I start it with "start": "node --trace-warnings dist/server/server.js",

I don't know if it's because I typed the res param with any or what it is..

Full Error:

TypeError: res.send is not a function
    at dist/server/api.js:58:9
    at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/node_modules/express/lib/router/index.js:317:13)

dist (output from TS and webpack)

  • TS is outputting my server folder code
  • webpack is outputting the rest via copy and bundling

webpack.config.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

const html = () => {
  return new HtmlWebPackPlugin({
    template: path.resolve(__dirname, 'src/client', 'index.html'),
    filename: 'index.html',
    hash: true,
  });
};

const copyAllOtherDistFiles = () => {
  return new CopyPlugin({
    patterns: [
      { from: 'src/client/assets', to: 'lib/assets' },
      { from: 'package.json', to: './' },
      { from: 'ext/ink-3.1.10/js/ink-all.min.js', to: 'lib/js' },
      { from: 'ext/ink-3.1.10/js/autoload.min.js', to: 'lib/js' },
      { from: 'ext/js/jquery-2.2.3.min.js', to: 'lib/js' },
      { from: 'ext/ink-3.1.10/css/ink.min.css', to: 'lib/css/ink.min.css' },
      { from: 'feed.xml', to: './' },
      {
        from: 'src/shared',
        to: './shared',
        globOptions: {
          ignore: ['**/*suppressed.json'],
        },
      },
    ],
  });
};

module.exports = {
  entry: './src/client/index.tsx',
  output: {
    filename: 'scripts/app.[hash].bundle.js',
    publicPath: '/',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  devtool: isProduction ? '' : 'inline-source-map',
  devServer: {
    writeToDisk: true,
    port: 8080,
  },
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.(tsx|ts)?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader',
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        loader: 'file-loader',
        options: {
          outputPath: 'lib/assets/fonts',
        },
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ['url-loader'],
      },
    ],
  },
  plugins: isProduction
    ? [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
          filename: isProduction ? 'lib/css/main.[hash].css' : 'main.css',
        }),
        html(),
        copyAllOtherDistFiles(),
      ]
    : [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};

./tsconfig.json

{
  "pilerOptions": {
    /* Visit .json to read more about this file */
    "target": "ES2015",                     /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "es2020",                     /* Specify module code generation: 'none', 'monjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "lib": ["es6", "dom"],                      /* Specify library files to be included in the pilation. */
        "moduleResolution": "node",
        "allowJs": true,                     /* Allow javascript files to be piled. */
        "checkJs": true,                     /* Report errors in .js files. */
    "jsx": "react",
    "noImplicitAny": true,
        "sourceMap": false,                   /* Generates corresponding '.map' file. */
    "rootDir": "./",                     /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
        "removeComments": true,              /* Do not emit ments to output. */
    "strict": true,                      /* Enable all strict type-checking options. */
        "noUnusedLocals": true,                /* Report errors on unused locals. */
        "noUnusedParameters": true,            /* Report errors on unused parameters. */
//    "rootDirs": ["."],                        /* List of root folders whose bined content represents the structure of the project at runtime. */
    "typeRoots": [
      "node_modules/@types"
    ],                      /* List of folders to include type definitions from. */
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
        "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
//      "resolveJsonModule": true,
        "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true
    },
    "include": [
        "src"
    ],
    "exclude": [
        "/node_modules",
        "/src/server",
        "/src/client/js/ink-config.js",
        "**/test"
  ]
}

./client/server/tsconfig.js (where server.ts and api.ts live)

{
    "extends": "../../tsconfig",
    "pilerOptions": {
        "outDir": "../../dist/server",                        
        "rootDir": "."                        
    },
    "include": ["./*.ts"]
}

./src/server/api.ts (api.js is outputted to dist/server)

const pression = require('pression'),
  express = require('express'),
  historyApi = require('connect-history-api-fallback'),
  oneYear = 31536000;

module.exports = express()
  .use(pression())
  .on('error', function (err: string) {
    console.log(err);
  })
  .use(historyApi())
  .use(
    express.static('dist', {
      maxage: oneYear,
    })
  )
  .use((res: any) => {
    res.send('Sorry, Page Not Found');
  });

I recently converted my build process over to using typescript and webpack. Now after resolving most the TS errors, I'm trying to run my site finally.

When I load the site, I'm getting TypeError: res.send is not a function from my expressjs static server. This code hasn't changed, it's always been the same even when I used gulp and worked fine but for some reason now after using webpack and TS, it's giving me this error now.

The server does indeed start on port 8080 and listens for requests. I start it with "start": "node --trace-warnings dist/server/server.js",

I don't know if it's because I typed the res param with any or what it is..

Full Error:

TypeError: res.send is not a function
    at dist/server/api.js:58:9
    at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/node_modules/express/lib/router/index.js:317:13)

dist (output from TS and webpack)

  • TS is outputting my server folder code
  • webpack is outputting the rest via copy and bundling

webpack.config.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

const html = () => {
  return new HtmlWebPackPlugin({
    template: path.resolve(__dirname, 'src/client', 'index.html'),
    filename: 'index.html',
    hash: true,
  });
};

const copyAllOtherDistFiles = () => {
  return new CopyPlugin({
    patterns: [
      { from: 'src/client/assets', to: 'lib/assets' },
      { from: 'package.json', to: './' },
      { from: 'ext/ink-3.1.10/js/ink-all.min.js', to: 'lib/js' },
      { from: 'ext/ink-3.1.10/js/autoload.min.js', to: 'lib/js' },
      { from: 'ext/js/jquery-2.2.3.min.js', to: 'lib/js' },
      { from: 'ext/ink-3.1.10/css/ink.min.css', to: 'lib/css/ink.min.css' },
      { from: 'feed.xml', to: './' },
      {
        from: 'src/shared',
        to: './shared',
        globOptions: {
          ignore: ['**/*suppressed.json'],
        },
      },
    ],
  });
};

module.exports = {
  entry: './src/client/index.tsx',
  output: {
    filename: 'scripts/app.[hash].bundle.js',
    publicPath: '/',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  devtool: isProduction ? '' : 'inline-source-map',
  devServer: {
    writeToDisk: true,
    port: 8080,
  },
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.(tsx|ts)?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader',
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        loader: 'file-loader',
        options: {
          outputPath: 'lib/assets/fonts',
        },
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ['url-loader'],
      },
    ],
  },
  plugins: isProduction
    ? [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
          filename: isProduction ? 'lib/css/main.[hash].css' : 'main.css',
        }),
        html(),
        copyAllOtherDistFiles(),
      ]
    : [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};

./tsconfig.json

{
  "pilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */
    "target": "ES2015",                     /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "es2020",                     /* Specify module code generation: 'none', 'monjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "lib": ["es6", "dom"],                      /* Specify library files to be included in the pilation. */
        "moduleResolution": "node",
        "allowJs": true,                     /* Allow javascript files to be piled. */
        "checkJs": true,                     /* Report errors in .js files. */
    "jsx": "react",
    "noImplicitAny": true,
        "sourceMap": false,                   /* Generates corresponding '.map' file. */
    "rootDir": "./",                     /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
        "removeComments": true,              /* Do not emit ments to output. */
    "strict": true,                      /* Enable all strict type-checking options. */
        "noUnusedLocals": true,                /* Report errors on unused locals. */
        "noUnusedParameters": true,            /* Report errors on unused parameters. */
//    "rootDirs": ["."],                        /* List of root folders whose bined content represents the structure of the project at runtime. */
    "typeRoots": [
      "node_modules/@types"
    ],                      /* List of folders to include type definitions from. */
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
        "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
//      "resolveJsonModule": true,
        "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true
    },
    "include": [
        "src"
    ],
    "exclude": [
        "/node_modules",
        "/src/server",
        "/src/client/js/ink-config.js",
        "**/test"
  ]
}

./client/server/tsconfig.js (where server.ts and api.ts live)

{
    "extends": "../../tsconfig",
    "pilerOptions": {
        "outDir": "../../dist/server",                        
        "rootDir": "."                        
    },
    "include": ["./*.ts"]
}

./src/server/api.ts (api.js is outputted to dist/server)

const pression = require('pression'),
  express = require('express'),
  historyApi = require('connect-history-api-fallback'),
  oneYear = 31536000;

module.exports = express()
  .use(pression())
  .on('error', function (err: string) {
    console.log(err);
  })
  .use(historyApi())
  .use(
    express.static('dist', {
      maxage: oneYear,
    })
  )
  .use((res: any) => {
    res.send('Sorry, Page Not Found');
  });
Share Improve this question edited Aug 3, 2020 at 3:51 PositiveGuy asked Aug 3, 2020 at 3:45 PositiveGuyPositiveGuy 20.4k30 gold badges94 silver badges152 bronze badges 1
  • 1 replace: .use((res: any) => { to: .use((req, res) => { or: .use((error, req, res, next) => { – num8er Commented Aug 3, 2020 at 3:52
Add a ment  | 

2 Answers 2

Reset to default 4

As @num8er writes in the ment, you need to correct the signature of the handler you passed to express.use(). Your code fails because the first parameter in that function is the request object, not the response object. The request object doesn't have a send() method, so you need to add at least two parameters if you're trying to send a response:

import express from 'express'

const app = express();

app.use((req, res) => {
    res.send()
})

The reason Typescript didn't catch this error is because you're using the any type. To actually get type checking, make sure you don't specify the type of either of those parameters as any. Instead, either:

  • Allow Typescript to correctly infer the type by removing the any; or
  • Specify the type explicitly:
import express from 'express'

const app = express();

app.use((req: express.Request, res: express.Response) => { 

})

Finally, make sure @types/express is installed.

You can check it out here:

https://www.typescriptlang/play/?ssl=1&ssc=1&pln=11&pc=3#code/JYWwDg9gTgLgBAUwB5iggzuuAzKERwDkyqG6hAUBQMYQB268AhmGHALyIpqYAUAlAG4qLMADoArugS9eaAI4AaOD34cAfHADecKgF9+I1pOmyFALi6lMYgEoJ5EjDGU9LJHujsZIDBGvZNHX1+IA

In my case where I have created an express server for my nuxtjs api,

res.end({})

works

本文标签: javascriptTypeError ressend is not a function when trying to load siteStack Overflow