Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server & client-side TypeScript project organization, compilation

How can I compile my TypeScript project what

  • Shares code between server & client
  • Uses TypeScript

I couldn't get webpack working, the website just shows a very basic getting started. I tried gulp, but it was far too complex and the incremental compilation took a very long time (way more than it should need).

src/
    common/
        data.ts
        [other files that are needed on both client and server-side]
    server/
        server.ts
        search.ts
    client/
        sw.ts
        resources/
             [other static resources like index.html]
[configuration files like package.json]

How can I do it? What should I use?

EDIT:

With gulp, I used gulp-typescript and tsify but the incremental compilation took more than 5 seconds, which was way too much.

like image 895
Tamás Avatar asked Aug 03 '26 22:08

Tamás


1 Answers

I use npm scripts to start 3 "watch" processes:

  • One that watches the client files (webpack) and compiles then into a folder called public.

  • One that watches the server files (tsc) and compiles then into a folder called private

  • One that watches the output server code (nodemon) and runs the node.js app when it changes.

Both apps can import files from common ans it should work fine.

My scripts config in package.json looks as follows:

  "scripts": {
    "watch-all": "npm run watch-server & npm run watch-client & nodemon --inspect private/server.js",
    "watch-server": "tsc -p tsconfig.json -inlineSourceMap -outDir private --watch",
    "watch-client": "webpack --watch",
  }

We have multiple standalone apps inside "client" and each app uses a folder. So we use webpack to create one bundle for each app.

My webpack config looks as follows (Note: there are some plugins that you may not need in this config):

const { CheckerPlugin, TsConfigPathsPlugin } = require("awesome-typescript-loader");
const Visualizer = require("webpack-visualizer-plugin");
const webpack = require("webpack");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const TypedocWebpackPlugin = require("typedoc-webpack-plugin");

const corePlugins = [
    new CheckerPlugin(),
    new webpack.DefinePlugin({
        "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development")
    }),
    new Visualizer({
        filename: "./debug/statistics.html"
    }),
    new CopyWebpackPlugin([
        // ...
    ])
];

const devPlugins = [
    new TypedocWebpackPlugin(
        {
            name: "ORG",
            out: "../private/docs",
            mode: "file",
            tsconfig: "./tsconfig.json"
        },
        "./src"
    )
];

const prodPlugins = [
    new webpack.optimize.UglifyJsPlugin()
];

const plugins = process.env.NODE_ENV === "production" ? corePlugins.concat(prodPlugins) : corePlugins.concat(devPlugins)

module.exports = {
    entry: {
        "app1/": "./src/client/app1/index.ts",
        "app2/": "./src/client/app2/index.ts",
        // ...
    },
    devServer: {
        inline: true
    },
    output: {
        filename: "[name]bundle.js",
        path: __dirname + "/public",
        publicPath: "/public"
    },
    devtool: "source-map",
    resolve: {
        extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"],
        plugins: [
            new TsConfigPathsPlugin({ configFileName: "tsconfig.json" })
        ]
    },
    module: {
        rules: [
            {
                enforce: "pre",
                test: /\.js$/,
                loader: "source-map-loader",
                exclude: [ /node_modules/, /experimental/ ]
            },
            {
                enforce: "pre",
                test: /\.(ts|tsx)$/,
                loader: "tslint-loader",
                exclude: [ /node_modules/, /experimental/ ]
            },
            {
                test: /\.(ts|tsx)$/,
                loader: "awesome-typescript-loader",
                exclude: [ /node_modules/, /experimental/ ]
            },
            {
                test: /\.scss$/,
                use: [{
                    loader: "style-loader",
                    options: {
                        sourceMap: true
                    }
                }, {
                    loader: "css-loader",
                    options: {
                        sourceMap: true
                    }
                }, {
                    loader: "sass-loader",
                    options: {
                        sourceMap: true
                    }
                }]
            }
        ]
    },
    plugins: plugins
};

I'm using the following versions:

  "devDependencies": {
    "awesome-typescript-loader": "^3.0.0-beta.18",
    "chai": "^3.5.0",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.28.0",
    "html5-history-api": "^4.2.7",
    "mocha": "^3.2.0",
    "node-sass": "^4.5.2",
    "nodemon": "^1.11.0",
    "nyc": "^10.1.2",
    "phantomjs-prebuilt": "^2.1.14",
    "sass-loader": "^6.0.3",
    "sequelize-auto": "^0.4.25",
    "sinon": "^2.0.0-pre.5",
    "source-map-loader": "^0.2.1",
    "sourcemap-istanbul-instrumenter-loader": "^0.2.0",
    "style-loader": "^0.16.1",
    "supertest": "^3.0.0",
    "tmp": "0.0.31",
    "ts-node": "^3.0.2",
    "tslib": "^1.6.0",
    "tslint": "^5.1.0",
    "tslint-loader": "^3.5.2",
    "typedoc": "^0.5.10",
    "typedoc-webpack-plugin": "^1.1.4",
    "typescript": "^2.2.2",
    "webpack": "^2.3.3",
    "webpack-dev-server": "^2.4.2",
    "webpack-visualizer-plugin": "^0.1.10",
    "xlsx": "^0.9.10",
    "yargs": "^7.0.2"
  }

Update 1 (Added tsconfig.json)

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["es6", "dom", "dom.iterable"],
        "downlevelIteration" : true,
        "module": "commonjs",
        "moduleResolution": "node",
        "jsx": "react",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "noImplicitAny": true,
        "preserveConstEnums": true,
        "suppressImplicitAnyIndexErrors": true,
        "strictNullChecks": true,
        "noImplicitReturns": false,
        "noImplicitThis": true,
        "baseUrl": "src",
    },
    "exclude": [
        "./node_modules"
    ]
}
like image 50
Remo H. Jansen Avatar answered Aug 06 '26 13:08

Remo H. Jansen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!