简体   繁体   中英

How do I configure webpack to display react component with typescript

So I'm trying to get my node project to render a simple react component, I'm using webpack for bundling

my package.json set's main entry point as webpack.config.js and has a srcipt to run webpack-dev-server. Here is my package.json :

{
"name": "@ruler-mobility/ruler",
"_comment": "main set to webpack's bundle file(home.tsx). this attr only explain main's purpose, delete it in the next merge ",
"main": "webpack.config.js",
"dependencies": {
    "@types/jest": "^25.1.3",
    "axios": "^0.19.1",
    "chalk": "^3.0.0",
    "compression": "^1.7.4",
    "cors": "^2.8.5",
    "errorhandler": "^1.5.1",
    "express": "^4.17.1",
    "express-session": "^1.16.2",
    "geolocation-utils": "^1.2.2",
    "jest": "^25.1.0",
    "jsonwebtoken": "^8.5.1",
    "node-sass": "^4.13.1",
    "numeral": "^2.0.6",
    "query-string": "^6.11.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "ts-jest": "^25.2.1",
    "typecast": "0.0.1",
    "winston": "^3.2.1"
},
"devDependencies": {
    "@types/compression": "^1.0.1",
    "@types/concurrently": "^4.1.0",
    "@types/cors": "^2.8.6",
    "@types/errorhandler": "^0.0.32",
    "@types/express": "^4.17.1",
    "@types/express-session": "^1.15.14",
    "@types/jsonwebtoken": "^8.3.6",
    "@types/node": "^12.12.25",
    "@types/numeral": "0.0.26",
    "@types/react": "^16.9.23",
    "@types/react-dom": "^16.9.5",
    "@types/ts-nameof": "^4.2.1",
    "@types/winston": "^2.4.4",
    "@typescript-eslint/eslint-plugin": "^2.18.0",
    "@typescript-eslint/parser": "^2.18.0",
    "cache-loader": "^4.1.0",
    "concurrently": "^5.0.0",
    "dotenv-webpack": "^1.7.0",
    "eslint": "^6.8.0",
    "eslint-config-prettier": "^6.9.0",
    "eslint-config-standard": "^14.1.0",
    "eslint-import-resolver-typescript": "^2.0.0",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-autofix": "0.0.9",
    "eslint-plugin-import": "^2.20.0",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-no-use-extend-native": "^0.4.1",
    "eslint-plugin-node": "^11.0.0",
    "eslint-plugin-prettier": "^3.1.2",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-react": "^7.18.0",
    "eslint-plugin-react-hooks": "^1.7.0",
    "eslint-plugin-sonarjs": "^0.5.0",
    "eslint-plugin-sort-imports-es6-autofix": "^0.5.0",
    "eslint-plugin-standard": "^4.0.1",
    "eslint-plugin-switch-case": "^1.1.2",
    "fork-ts-checker-webpack-plugin": "^4.0.4",
    "jest-extended": "^0.11.4",
    "nodemon": "^1.19.2",
    "prettier": "^1.19.1",
    "ts-loader": "^6.2.1",
    "ts-nameof": "^4.2.2",
    "ts-node": "^8.6.2",
    "tsconfig-paths-webpack-plugin": "^3.2.0",
    "typescript": "^3.7.5",
    "webpack": "^4.41.6",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.3",
    "webpack-merge": "^4.2.2",
    "webpack-node-externals": "^1.7.2"
},
"repository": {
    "type": "git",
    "url": "git+https://bitbucket.org/ruler-mobility/ruler.git"
},
"scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --mode=production",
    "lint": "eslint . --quiet --fix --ext js,jsx,ts,tsx",
    "test": "jest --forceExit --coverage --verbose",
    "watch-test": "npm run test -- --watchAll",
    "stop-win": "Taskkill /IM node.exe /F",
    "stop-linux": "killall node"
},
"version": "1.0.0"
 }

my webpack.config.js sets Home.tsx as entry point for the what to bundle and the output file's path in a parent folder. here is how it looks:

const path = require('path');
const chalk = require('chalk');
const merge = require('webpack-merge');
const Dotenv = require('dotenv-webpack');
 const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
 const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
 const nodeExternals = require('webpack-node-externals');
 const tsNameof = require('ts-nameof');
 const { PORT } = process.env;

module.exports = (env = {}, argv = {}) => {
const { mode } = argv;
const production = mode === 'production';
const development = !production;

console.log(
    chalk.blue(`The current build process is running in ${chalk.underline((production ? 'production' : 'development').toUpperCase())} mode`)
);

return merge(
    {
        devtool: production ? 'eval' : 'cheap-module-eval-source-map'
    },
    development && {
        optimization: {
            removeAvailableModules: false,
            removeEmptyChunks: false,
            splitChunks: false
        },
        output: {
            pathinfo: false
        }
    },
    {
        context: __dirname,
        target: 'node',
  externals: [nodeExternals()],
  //set the entry point to our app(the front-end)
        entry: path.resolve(__dirname, './front-end/components/Home.tsx'),
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    use: [
                        'cache-loader',
                        {
                            loader: 'ts-loader',
                            options: {
                                transpileOnly: true,
                                happyPackMode: true
                            }
                        },
                        {
                            loader: 'eslint-loader',
                            options: {
                                fix: true,
                                quiet: true,
                                // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
                                getCustomTransformers: () => ({ before: [tsNameof] })
                            }
                        }
                    ],
                    exclude: /node_modules/
                }
            ]
        },
        plugins: [new Dotenv(), new ForkTsCheckerWebpackPlugin({ checkSyntacticErrors: true })],
        resolve: {
            extensions: ['.js', '.jsx', '.ts', '.tsx'],
            plugins: [
                new TsconfigPathsPlugin({
                    configFile: 'tsconfig.json'
                })
            ]
  },
  // output set's the path for front-end bundle file
        output: {
    path: path.resolve(__dirname, 'front-end/dist'),
            filename: 'home.js'

        },
        devServer: {
            contentBase: path.join(__dirname, 'front-end/dist'),
            compress: true,
            open: true,
            hot: true,
            port: PORT || 3000
        }
    }
);
 };

So I expect webpack to bundle my files(which will include everything my Home.tsx uses) in the front-end/dist directory under the name home.js

here is how I setup my Home . I have a index html at the path front-end/index.html that contains:

<body>
    <div class="container"></div>
    <h1>Hello</h1>
    <script src="/front-end/dist/home.js"></script>
</body>

AND my Home.jsx:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

const ROOT = document.querySelector('.container');
ReactDOM.render(<h1>HELLO 2</h1>, ROOT);

When I run npm run script start and open localhost:3000, I get my browser showing me all the files in the front-end/dist directory, which is the home.js file. Shouldn't it load the Home.tsx file because that is what I have set as the entry point in webpack. How do I configure webpack to display 'home.tsx' at the root ie localhost:3000.

plus here my tsconfig file:

 {
"compilerOptions": {
    "alwaysStrict": true,
    "module": "commonjs",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "jsx": "react",
    "lib": ["es6", "dom"],
    "target": "es6",
    "noImplicitAny": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
        "*": ["node_modules/*"],
        "@ruler": ["src", "packages"],
        "@ruler/*": ["src/*", "packages/*"],
        "@ruler/configs": ["configs"],
        "@ruler/configs/*": ["configs/*"],
        "@ruler/test": ["test"],
        "@ruler/test/*": ["test/*"],
        "@ruler/types": ["types"],
        "@ruler/types/*": ["types/*"]
    }
},
"exclude": ["node_modules", "**/*.spec.ts"]
}

file structure:

 Project
       |
       +-- package.json
       |    
       +-- tsconfig.json
       |   
       +-- webpack.config.js
       |   
       +-- front-end 
       |           |  
                   +-- components
                   |            |
                   |             +-- Home.tsx
                   |
                   +--index.html

Note: these are only the files used for the set-up, the project consists of more but I don't they're needed to be mentioned

It looks to me that you are referring to a wrong file. Because you have mentioned a .tsx file but your actual file is a .jsx file. So i feel you should add .jsx instead:

entry: path.resolve(__dirname, './front-end/components/Home.jsx')

or you should rename your file to Home.tsx .

First of all if you need to add typescript support to your webpack config you need to add '.ts' and '.tsx' as resolvable extensions abd add a specific loader rule for ts files support.

 resolve: {
        extensions: [".ts", ".tsx"]
    },
 module: {
        rules: [
            {
                test: /\.ts(x?)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: "ts-loader"
                    }
                ]
            },
            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            {
                enforce: "pre",
                test: /\.js$/,
                loader: "source-map-loader"
            }
        ]
    },

your home.js is the bundled file generated by webpack as an output after transpiling your entry file which will be either your Home.jsx or your Home.tsx.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM