天天看點

webpack開發環境與生産環境分離

開發環境(development)和生産環境(production)的建構目标差異很大。在開發環境中,我們需要具有強大的、具有實時重新加載(live reloading)或熱子產品替換(hot module replacement)能力的 source map 和 localhost server。而在生産環境中,我們的目标則轉向于關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。由于要遵循邏輯分離,我們通常建議為每個環境編寫彼此獨立的 webpack 配置。

雖然,以上我們将生産環境和開發環境做了略微區分,但是,請注意,我們還是會遵循不重複原則(Don’t repeat yourself - DRY),保留一個“通用”配置。為了将這些配置合并在一起,我們将使用一個名為 webpack-merge 的工具。通過“通用”配置,我們不必在環境特定(environment-specific)的配置中重複代碼。

注:示例的完整代碼請參考《Webpack整合執行個體及優化》

安裝

推薦使用項目局部安裝:在 package.json 中添加如下配置,并進行安裝

“webpack-merge”: “^4.1.1”,

配置檔案分離

webpack開發環境與生産環境分離

webpack.common.js

const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: {
        app: "./js/requireAddDiv.js"
    },
    module: {
        rules: [
            {
                test: /\.(jsx|js)$/,
                use: {
                    loader: "babel-loader?cacheDirectory=true", // 使用cache提升編譯速度
                    options: {
                        presets: ["env", "react"],
                        plugins: ["transform-runtime"]// 避免重複引入
                    }
                },
                exclude: /node_modules/
            },
            {// 分離 css
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: "css-loader"
                })
            },
            {
                test: /\.html$/,
                use: "html-loader"
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(["dist"]),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, "index.temp.html")
        })
    ]
};
           

webpack.dev.js

const merge = require("webpack-merge");
const common = require("./webpack.common");
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = merge(common, {
    devtool: "eval-source-map", // 僅在開發過程中使用
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.[hash].js"
    },
    devServer: {
        contentBase: "./",
        historyApiFallback: true,
        inline: true
        // hot: true // hot module replacement. Depends on HotModuleReplacementPlugin
    },
    module: {
        rules: [
            {// 處理圖檔,會在 output 目錄中生成圖檔檔案,js 中需要使用 require("*.jpg")先行引入才可以,同樣 html 中通過 background-image 設定的圖檔不可以,但 css 中通過 background-image 設定的圖檔可以
                test: /\.(jpg|png)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        outputPath: "images/", // 這裡的 images 貌似沒什麼作用,但不寫不行,可以是任意的一個或多個字元
                        name: "[name].[hash:8].[ext]", // 8表示截取 hash 的長度
                        useRelativePath: true// 這個必須與 outputPath 結合使用才可以處理 css 中的引入的圖檔
                    }
                }
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("css/styles-[hash].css") // 可以單獨設定css的路徑
        // new webpack.NamedModulesPlugin(), // 以便更容易檢視要修補(patch)的依賴
        // new webpack.HotModuleReplacementPlugin() // 使用 hot 導緻頁面不能自動重新整理?
    ]
});
           

webpack.prod.js

const merge = require("webpack-merge");
const common = require("./webpack.common");
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = merge(common, {
    devtool: "source-map",//生産環境也可以設定,有點兒影響性能,但友善調試
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js"
    },
    module: {
        rules: [
            {// 處理圖檔,會在 output 目錄中生成圖檔檔案,js 中需要使用 require("*.jpg")先行引入才可以,同樣 html 中通過 background-image 設定的圖檔不可以,但 css 中通過 background-image 設定的圖檔可以
                test: /\.(jpg|png)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        outputPath: "images/", // 這裡的 images 貌似沒什麼作用,但不寫不行,可以是任意的一個或多個字元
                        name: "[name].[ext]",
                        useRelativePath: true// 這個必須與 outputPath 結合使用才可以處理 css 中的引入的圖檔
                    }
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin("版權所有,盜版必究!"),
        new webpack.DefinePlugin({
            "process.env": {
                "NODE_ENV": JSON.stringify("production")
            }
        }),
        // new webpack.optimize.OccurrenceOrderPlugin(), // 現在是預設啟用,不再需要手動啟動
        new webpack.optimize.UglifyJsPlugin({
            output: {
                comments: false// remove all comments
            },
            compress: {
                warnings: false
            },
            sourceMap: true // 如果你在壓縮代碼時啟用了 source map,或者想要讓 uglifyjs 的警告能夠對應到正确的代碼行,你需要将 UglifyJsPlugin 的 sourceMap 設為 true。
        }),
        new ExtractTextPlugin("css/styles.css") // 可以單獨設定css的路徑
    ]
});
           

package.json

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "This is just a test",
  "main": "dist/bundle.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "keywords": [
    "webpack",
    "dev-server"
  ],
  "author": "slHuang",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.4",
    "webpack-merge": "^4.1.1",
    "style-loader": "^0.19.0",
    "css-loader": "^0.28.7",
    "postcss-loader": "^2.0.8",
    "autoprefixer": "^7.1.6",
    "babel-core": "^6.26.0",
    "babel-cli": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-react": "^6.24.1",
    "babel-preset-env": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "extract-text-webpack-plugin": "^3.0.2",
    "clean-webpack-plugin": "^0.1.17",
    "html-loader": "^0.5.1",
    "file-loader": "^1.1.5",
    "eslint": "^4.11.0"
  },
  "dependencies": {
    "babel-runtime": "^6.26.0"
  }
}
           

運作 start 為開發環境,

運作 build 為生産環境。