1. 程式人生 > >webpack4+react+typescript搭建demo

webpack4+react+typescript搭建demo

最近寫了個用react+webpack+typescript搭建的demo

目錄結構如下:

package.json:

{
  "name": "react-webpack-cms",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.tsx",
  "scripts": {
    "build-dev": "cross-env NODE_ENV=development webpack --config ./bin/webpack.dev.config.js --colors",
    "build-proc": "cross-env NODE_ENV=production webpack  --config ./bin/webpack.proc.config.js --colors",
    "dev":"cross-env NODE_ENV=development node ./bin/dev-server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/react": "^16.4.12",
    "@types/react-dom": "^16.0.7",
    "react": "^16.4.2",
    "react-dom": "^16.4.2"
  },
  "devDependencies": {
    "autoprefixer": "^9.1.3",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-es2015": "^6.24.1",
    "clean-webpack-plugin": "^0.1.19",
    "cross-env": "^5.2.0",
    "css-loader": "^1.0.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^2.0.0",
    "fs": "^0.0.1-security",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.9.3",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "source-map-loader": "^0.2.4",
    "style-loader": "^0.23.0",
    "ts-loader": "^4.5.0",
    "uglifyjs-webpack-plugin": "^1.3.0",
    "webpack": "^4.17.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.6",
    "webpack-merge": "^4.1.4"
  }
}

tsconfig.json:

{
  "version": "2.5.3",
  "compilerOptions": {
    "jsx": "react",
    "module": "commonjs",
    "target": "es5",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "outDir": "dist",
    "sourceMap": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

index.tsx:

import * as React from "react"
import * as ReactDOM from "react-dom"

ReactDOM.render(
    <div>Hello world</div>,
    document.getElementById('app')
);
// console.log(1);

GetEAP.js獲取plugins:

const path = require('path');
const webpack = require('webpack');
const __DEV__ = process.env.NODE_ENV !== 'production';
/**
 * extract-text-webpack-plugin外掛
 * TODO: 將樣式提取到單獨的css檔案中不將css打包到js中
 */
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
/**
 * html-webpak-plugin外掛,生成html外掛
 * TODO: https://www.npmjs.com/package/html-webpack-plugin
 */
const HtmlWebpackPlugin = require('html-webpack-plugin');
/**
 * clean-webpack-plugin外掛
 * TODO: 熱更新刪除打包的檔案
 */
const CleanWebpackPlugin = require('clean-webpack-plugin');

/**
 * TODO: getPlugins
 */
class getPlugins {
    constructor() {
        var plugins = [
            new webpack.optimize.RuntimeChunkPlugin({
                name: "manifest"
            }),
            new ExtractTextWebpackPlugin('static/css/[name].css'),
            new HtmlWebpackPlugin({
                favicon: path.join(__dirname, '..', 'static', 'favicon.ico'),
                filename: 'index.html',
                template: './src/index.html',
                inject: 'body',
                hash: true,
                chunks: ['main', 'manifest', 'vendor'],
                minify: {
                    removeComments: true,
                    collapseWhitespace: false
                }
            }),
            new webpack.HotModuleReplacementPlugin(),
        ];
        if (!__DEV__) {
            plugins.push(new CleanWebpackPlugin('dist/', {
                root: path.join(__dirname, '..'),
                verbose: true,
                dry: false
            }));
        }
        return plugins;
    }
}


module.exports = getPlugins;

webpack.base.config.js:

const __DEV__ = process.env.NODE_ENV !== 'production';
const path = require('path');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const GetEAP = require('../lib/GetEAP');
const config = require('../lib/config');
module.exports = {
    mode: __DEV__ ? 'development' : 'production',
    entry: [path.resolve(__dirname, '..', 'src', 'index.tsx')],
    output: {
        path: path.resolve(__dirname, '..', 'dist'),
        publicPath: __DEV__ ? config.dev.assertPublicPath : config.proc.assertPublicPath,
    },
    module: {
        rules: [{
            test: /\.(css|scss)$/,
            use: ExtractTextWebpackPlugin.extract({
                fallback: 'style-loader',
                use: [{
                    loader: 'css-loader',
                    // options: {
                    //     minimize: true
                    // }
                }, 'postcss-loader', 'sass-loader']
            })
        }, {
            test: /\.html$/,
            loader: 'html-loader?attrs=img:src img:data-src',
        }, {
            test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
            loader: 'file-loader?limit=1024&name=static/fonts/[name].[ext]'
        }, {
            test: /\.js$/,
            use: ['babel-loader', 'source-map-loader'],
            exclude: /node_modules/
        }, {
            test: /\.tsx?$/,
            loader: 'ts-loader',
            exclude: /node_modules/
        }]
    },
    plugins: new GetEAP(),
    node: {
        fs: 'empty'
    },
};

webpack.dev.config.json:

const merge = require('webpack-merge');
const webpackBaseConfig = require('./webpack.base.config');
const path = require('path');
const config = require('../lib/config');

module.exports = merge(webpackBaseConfig, {
    output: {
        path: path.join(__dirname, '..', 'dist'),
        publicPath: config.dev.assertPublicPath,
        filename: 'static/js/[name].js',
        hotUpdateChunkFilename: './static/hot/hot-update.js',
        hotUpdateMainFilename: './static/hot/hot-update.json'
    },
    devtool: 'source-map',
    resolve: {
        extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js', '.jsx']
    },
});

webpack.proc.config.json:

const merge = require('webpack-merge');
const path = require('path');
const webpackBaseConfig = require('./webpack.base.config');
const config  = require('../lib/config');

module.exports = merge(webpackBaseConfig, {
    output: {
        path: path.resolve(__dirname, '..', 'dist'),
        publicPath: config.proc.assertPublicPath,
        filename: 'static/js/[name].[hash].min.js',
    },
});

config.js

module.exports = {
    dev: {
        assertPublicPath: './',
        port: '8080'
    },
    proc: {
        assertPublicPath: './',
    }
};