简体   繁体   中英

how to make webpack typescript react webpack-dev-server configuration for auto building and reloading page

My intention is to have such directory structure:

- /my-project/
  -- /src/ (here are all .tsx files located)
  -- /dist/
     - index.html
     - /build/
        -bundle.js

 -- /node_modules/
 -- package.json
 -- tsconfig.json
 -- webpack.config.js

So, I want to have my index.html which is made manually in the /dist subdirectory and inside of it I want to have /build subdir where the app.js made by webpack goes.

And I want when I'm saving some .tsx file located in my /src dir webpack automatically rebuild app.js and webpack-dev-server automatically reflect the changes.

My package.json looks like this:

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "My first React App",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --content-base ./dist --hot --inline --colors --port 3000 --open",
    "build": "webpack --config webpack.config.js --watch",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "AndreyKo",
  "license": "ISC",
  "devDependencies": {
    "@types/react": "^0.14.54",
    "@types/react-dom": "^0.14.19",
    "jquery": "^3.1.1",
    "source-map-loader": "^0.1.5",
    "ts-loader": "^1.3.0",
    "typescript": "^2.1.4",
    "webpack": "^1.14.0",
    "webpack-dev-server": "^1.16.2"
  },
  "dependencies": {
    "react": "^15.4.1",
    "react-dom": "^15.4.1"
  }
}

My webpack.config.js :

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "app.js",
        publicPath: "/dist/",
        path: "./dist/build/"
    },
    dev_tool: "source-map",
    resolve: {
        extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js']
    },
    module: {
        loaders: [
            {test: /\.tsx?$/, loader: 'ts-loader'}
        ],
        preloaders: [
            {test: /\.js$/, loader: 'source-map-loader'}
        ]
    }
}

My index.html :

<!DOCTYPE html>
<html>
    <body>
        <div id="app-container"></div>
    </body>
    <script src="./build/app.js"></script>
</html>

And my index.tsx file looks like this:

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

function appOutput() {
    ReactDOM.render(<div>Hello, we are talking from React!</div>, document.getElementById("app-container"));
}
appOutput();

I've done commands to the terminal:

npm run build
npm run start

So the app.js was created and webpack-dev-server started working and opened page in the browser. Everything goes fine by far. But when I change the text in my index.tsx and save this file nothing changes, I tried to refresh the browser page, the text remains the same and app.js is not rebuilt. To make the text change I have to rebuild app.js with webpack by hand again from the terminal by issuing "npm run build".

How to improve my workflow to make the changes in my /src folder be reflected automatically in my dist/build/app.js file without having to manually rebuild it?

I put here more complete and (what is more important) more correct answer for anybody who may stumble upon the configuration of dev environment for react-webpack-typescript development. Somehow reading documentation was not good enough for me and I had to spend more than a day to make it work.

So I wanted to get the directory structure where bundled javascript files lie one level deeper than html index.html file. Look at the initial post for the full directory structure.

And as a developer I wanted when I change some .tsx file in /src folder my changes be reflected in the browser and also we need to recompile bundled .js file. For these purposes there are two scripts are created in the scripts block of package.json file of the project:

  "scripts": {
    "start": "webpack-dev-server --content-base ./dist --hot --inline --colors --port 3000 --open",
    "build": "webpack --config webpack.config.js --watch",
  }

The first one starts webpack-dev-server providing the root directory /dist for it to serve and --hot --inline keys for it to automatically reload browser page and to get rid of unnecessary iframe. There is also --port defined and auto page --open when webpack-dev-server is started.

The second command is for auto rebuilding of the bundled app.js by webpack thanks to the --watch key.

And for these commands to work as expected the webpack should be properly configured in webpack.config.js. And the most delicate part for me (and for many others as I later saw) was the correct path, publicPath and filename settings of the output block. There is a mistake in my initial post in the publicPath which made my webpack-dev-server not working.

Not working output block was:

output: {
    filename: "app.js",
    publicPath: "/dist/",
    path: "./dist/build/"
}

The output block which works is:

output: {
    filename: "app.js",
    publicPath: "/build/",
    path: "./dist/build/"
}

publicPath property is used by the webpack-dev-server to refresh the browser page and it should be set to the directory where your compiled .js files lie relative to the root server directory which is set by --content-base key in my start script and refers to ./dist inside my project. So the correct value is /build/ and not /dist/.

path and filename properties are used by webpack and command where to put and how to name the bundled .js file. In my case the ./dist/build/app.js file will be created.

One more thing that is certainly present in docs but I'd like to mension here is that when I save some .tsx file after I started my webpack-dev-server with my start script but haven't run the build command (which makes webpack watch changes) I get the updated results in the browser but my bundled app.js file is not changed. And this is because the webpack-dev-server only updates the in-memory copy of bundled .js file and not the file itself. To syncronize we need to rebuild the bundle with webpack.

If I want my bundled .js file to stay in syncro with the browser page I need to make webpack watch changes and webpack-dev-server to make hot reload of the page, so I run both "start" and "build" scripts. But I can't run both of them from one command prompt on my windows dev machine, so I run each of them in separate with:

This is valid only for windows!

start npm run start && start npm run build

And for the sake of my fingers I put this line into the run.bat file which is put into the project folder. Now I can just open the windows terminal in VSCode editor and issue the command "run" there.

That's it for now.

Ok, so I've managed to solve my problem though not perfectly.

As it looks like it depends of the OS and other environment I want to be precise: my OS - windows7 my editor - VS Code.

First of all I'd like to note that my installation works as I needed without any adjustments.

But it doesn't work when I run my build and start commands from the VS Code terminal.

To make this work I had to open two separate terminal windows and in the first of them I run my build script and in the second my start script:

first Terminal > npm run build
second Terminal > npm run start

Another way of doing this right from VS Code's terminal is to issue there such command:

start npm run start && start npm run build 

which does absolutely the same - opens two terminal windows and runs npm commands in these windows.

Finally I made a run.bat file where I put this line and now I can just open my project in VS Code and in the terminal run command "run" and webpack and webpack-dev-server start watching for changes.

That's it. If there are better ways, please point me out, I'm opened to more elegant ways to solve it.

使用当前版本的 webpack 工具,应该安装 webpack-cli (npm install webpack-cli --save-dev) 并使用:

webpack-cli serve --config ./webpack.config.js

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