自己搭建React+Webpack開發環境並性能優化

引言

之前我的用fb的create-react-app來直接開發,直接用npm install,之後放到Heroku也是超級不用腦的XD 之後隨著自己越來越上手,發現自己src文件夾下跟我房間一樣亂(誤,想嘗試自己手把手搭建整個開發環境,順便把文件整理。

開始

一開始我看的文章是 [1]从零搭建React全家桶框架教程,根據他提供的指令搭建。下面是我看了他的文章,找出需要用到的元件指令,在專案根目錄下的cmd打上:

npm init
npm install --save-dev-g webpack    //新增webpack.config.js exports....
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
    //新增babel文件 presets等等....
    //開始在Index.js寫react的東西
    //加上方便的指令
npm install --save react-router-dom
npm install webpack-dev-server --save-dev
npm install react-hot-loader@next --save-dev
npm install --save-dev css-loader
npm install --save-dev file-loader
npm install style-loader --save-dev
npm install --save-dev url-loader   //這是用來引入圖片
npm install axios

Webpack是用來打包各種文件,像是CSS、JS檔、Module、Babel、背景圖片等等,非常的好用!Babel組件把ES6,ES7的語法轉換成ES5,css-loader,file-loader,style-loader,url-loader都是webpack用來打包css、圖案的組件。

優化

在裝完各種檔案(Package.json、webpack.config.js、.babelrc我會放下面)後,再來做優化:

  1. npm dedupe[2](安裝檔案都需要)
    安裝完node package後,需要這個指令來重新整理,會發現node_modules文件夾會變小哦!

  2. CommonsChunkPlugin
    他會把大家共用的JS檔案拿出來,減少重複的檔案。

  3. UglifyJSPlugin
    會壓縮JS檔案,讓體積變小。

  4. 把React換成Production版本
    減少原本react中的註釋和空白。

    new webpack.DefinePlugin({
        'process.env': {
            NODE_ENV: JSON.stringify(process.env.NODE_ENV),
        },
    }),
    

經過這四招,我把檔案從快1MB減到300KB++,下面是我Webpack的檔案

Webpack設定檔

const path = require('path');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

const srcPath = path.resolve(__dirname, 'src');
const distPath = path.resolve(__dirname, 'dist');

module.exports = {
    /*devtool讓我在borwser看到哪裡出問題*/
    devtool: 'cheap-module-eval-source-map',
    context: srcPath,
    /*入口*/
    entry: [
        path.join(__dirname, 'src/index.js'),
    ],  
    /*输出到dist文件夹,输出文件名字为bundle.js*/
    output: {
        path: path.join(__dirname, './dist'),
        filename: 'bundle.js'
    },

    /*src文件夹下面的以.js结尾的文件,要使用babel解析*/
    /*cacheDirectory是用来缓存编译结果,下次编译加速*/
    module: {
        rules: [
            {
                test: /\.js$/ ,
                loader:['babel-loader?cacheDirectory=true'],
                exclude: '/node_modules/'},
            {
                test: /\.jsx$/ ,
                loader:['babel-loader?cacheDirectory=true'],
                exclude: '/node_modules/'},

            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options : {
                            url: false
                        }
                    }
                ]},
            {
                test: /\.(png|jpg|gif)$/,
                exclude: /node_modules/,
                use: [{
                    loader: 'url-loader',
                    options: {
                        limit: 25000
                    }
                }]    
            }]
    },

    devServer: {
        contentBase: path.join(__dirname, './dist'),
        historyApiFallback: true,
        host: '0.0.0.0',
        port: process.env.PORT || 8080,
        public: 'forecastapps.herokuapp.com'
    },

    resolve: {
        //bug of webpack:
        //https://github.com/webpack-contrib/css-loader/issues/74
        modules: ['./', 'node_modules'],
        alias: {
            images: path.join(__dirname, './dist/images'),
            owfont: path.join(__dirname, 'src/component/Forecast/owfont-master'),
            Api: path.join(__dirname, 'src/component/Api'),
            Today: path.join(__dirname, 'src/component/Today'),
            Forecast: path.join(__dirname, 'src/component/Forecast'),
            component: path.join(__dirname, 'src/component'),
            router: path.join(__dirname, 'src/router'),
        }
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        filename: 'vendor.bundle.js',
        minChunks: 2
        }), 
        new UglifyJSPlugin(),
        new webpack.DefinePlugin({
            'process.env': {
            'NODE_ENV': JSON.stringify('production')
            }
        }),
    ],
};    

Package.json(一部分)

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev-build": "webpack --config webpack.config.js",
    "start": "set NODE_ENV=production&&webpack-dev-server --config webpack.config.js -p --progress --colors",
    "dev": "webpack-dev-server --config webpack.config.js --color --progress --hot",
}

.babelrc

{
    // compact用來蓋掉在compiler的時候,出現的"The code generator has deoptimised the styling of [some file] as it exceeds the max of "500KB" [3]"訊息
    "compact": "false",
    "presets": [
        "es2015",
        "react",
        "stage-0"
    ],
    "plugins": [
        "react-hot-loader/babel"
    ]
}

Hot Module Replacement

這邊我有不太明白的地方,就是關於Hot Module Replacement。Hot Module Replacement就是在我開發時,能在我保存後,更新我修改的那部分,不需要我手動刷新。但在使用後,發現一個問題:State每次在我保存後,會被重置。我嘗試了react-hot-loader,發現不知道怎麼弄QQ看有誰路過能指點一下XD

參考資料

  1. https://github.com/brickspert/blog/issues/1
  2. http://www.alloyteam.com/2016/03/master-npm/
  3. https://tutel.me/c/programming/questions/29576341/what+does+quotthe+code+generator+has+deoptimised+the+styling+of+some+file+as+it+exceeds+the+max+of+quot100kbquotquot+mean
  4. https://github.com/reactjs/redux/issues/809