webpack4生產環境和開發環境的對比

前言

近期一直在看webpack4的文檔,因而給本身作了這個總結,對比一下生產環境和開發環境的區別。javascript

開發環境

在項目開發過程當中,咱們關注的是可否追溯到代碼的錯誤來源,可以及時刷新頁面讓咱們看到代碼的實際效果,所以webpack針對開發特色提供了幾個插件。css

source-map

webpack會將代碼打包至一個文件中,一旦發生錯誤和警告,很難追溯到其來源,所以webpack提供了source-map,將編譯後的代碼映射回原始代碼。java

官網示例代碼結果如圖:node

source-map有多種使用方式,官方推薦三種使用方式:devtool, SourceMapDevToolPlugin或EvalSourceMapDevToolPlugin。第一種採用的是內置插件,第2、第三種是直接插入插件。三種方式不能同時出現,不然會致使插件被置入兩次。webpack

devtoolweb

devtool: 'inline-source-map',
複製代碼

webpack官網中列舉出來了一些devtool屬性的性能對比(地址),咱們能夠根據本身項目的須要來選用。npm

插件能夠對source-map生成更細粒度的控制,能夠做爲插件使用,也能夠在經過devtool的某些設置來自動開啓json

SourceMapDevToolPlugin後端

new webpack.SourceMapDevToolPlugin(options);
複製代碼

在使用TerserPlugin時,您必須使用該sourceMap選項。api

EvalSourceMapDevToolPlugin

new webpack.EvalSourceMapDevToolPlugin(options);
複製代碼

開發工具

每次編寫完代碼後都須要運行npm run build很是麻煩,所以webpack提供了三種不一樣的開發工具支持實時更新代碼。

1. webpack's Watch Mode

經過添加npm腳本的方式來監控代碼的變化,在package.json中添加一行

"scripts": {
	"watch": "webpack --watch"
}
複製代碼

此時啓動npm run watch即可以監控代碼,咱們能夠查看到文件的hash值一直在變化,表示文件一直在跟隨代碼的更新而變化。

可是這個方式依舊須要開發人員手動刷新瀏覽器才能看到更改,所以使用者很少。

2. webpack-dev-server

該方法提供一個簡單的web服務器和使用實時從新加載的能力。所以是使用較多的一個工具。webpack-dev-server從devServer中讀取配置,

devServer: {
    contentBase: './dist'
}
複製代碼

contentBase告訴webpack-dev-server從dist目錄中提供文件,顯示在localhost:8080上。

webpack-dev-server並不會輸出編譯後的文件,而是將文件保存在內存中提供服務,開啓本地服務器來監控代碼並實時刷新網頁。

webpack-dev-server開啓的是本地服務器,而一般咱們在開發過程當中須要與後端進行通訊,調試數據。本地服務器會有跨域問題,所以咱們能夠經過devServer設置代理來請求接口

devServer: {
    proxy: {
        '/api': 'http://localhost:3000'
    }
}
複製代碼

固然咱們也能夠經過一些代理軟件來對處理本地請求的問題,只是webpack-dev-server本身也實現了這個功能。

更多具體的配置能夠查閱官網文檔

3. webpack-dev-middleware

webpack-dev-middleware是一個包裝器,將webpack處理後的文件發送到服務器,在webpack-dev-server內部也是經過這個中間件來實現的,也能夠做爲單獨的包提供,容許更多自定義設置。

webpack-dev-middleware在使用時須要配置output的publicPath屬性,以確保正確提供文件。添加文件server.js, 在該文件中設置相應的自定義,即可以啓動中間件運行。下面是官網的自定義示例:

生產環境

生產環境與開發環境徹底不一樣,在生產環境中咱們關注的是如何才能產生更小的代碼塊,壓縮文件的體積,使得加載時間作到最短。

source mapping

webpack鼓勵開發人員在生產環境中也加入source-map,便於調試和運行基準測試。在生產環境中應當選擇構建速度較快的source-map,儘可能避免在生產環境中使用inline-*** 或 eval-*** 的source-map,由於它們會顯著增長包的體積並下降總體性能。

推薦配置:devtool: 'source-map'

壓縮css

優化css代碼是生產構建中很是重要的一環,webpack4+爲此專門提供了一個css插件:MiniCssExtractPlugin,爲每一個包含CSS的JS文件建立一個CSS文件。它支持CSS和SourceMaps的按需加載。 與以前使用的extract-text-webpack-plugin插件(webpack4+已廢棄)相比,webpack4提供的這個插件具備更加顯著的優勢:異步加載、沒有重複編譯、性能更加良好、更容易使用、定製css。並且官網指明在將來這個插件有可能會支持熱重載。

須要注意的是,MiniCssExtractPlugin只應該在生產環境中被使用,並且在生產環境中應該使用它來替代style-loader。同時配合插件optimize-css-assets-webpack-plugin來壓縮css文件。

module.exports = {
    optimization: {
    minimizer: [
      new TerserJSPlugin({}), // 須要顯式的指定js minimalizer,由於optimization.minimizer會覆蓋默認設置
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader"
        ]
      }
    ]
  }
}
module: {
    rules: [
        {
            test: /\.css$/,
            use: [
                MiniCssExtractPlugin.loader,
                "css-loader"
            ]
        }
    ]
}
複製代碼

Tree Shaking

tree shaking是Javascript上下文中去除死代碼的一個術語,它依賴於ES5的模塊語法的靜態結構,即import和export語法。在webpack2中已內置支持ES2015的模塊語法,在webpack4中隊這一功能進行了擴充,經過package.json中的'sideEffects'來標識項目中哪些文件是純粹的,若是未使用則能夠安全修建。 可是在使用tree shaking時須要注意,只有無反作用的代碼才能夠應用修剪,

「反作用」定義爲在導入時執行特殊行爲的代碼,而不是公開一個或多個導出。一個例子是polyfill,它影響全局範圍,一般不提供導出。

在webpack4以上的環境中,在package.json中添加'sideEffects'屬性,並將mode設置爲production便可開啓tree shaking。固然,tree shaking只是標識出能夠被修剪掉的代碼塊,最後仍是須要使用UglifyjsWebpackPlugin插件來進行js壓縮。

注意:tree shaking只支持ES6模塊語法,不能識別CommonJS語法,由於CommonJS是動態導入,沒法被識別

通用功能

Code Splitting

在使用webpack的時候,咱們都會學到一個概念,webpack會將全部代碼都打包到一個文件中去,形成該文件的體積十分的龐大,所以webpack提供了代碼拆分功能,咱們能夠將一些代碼提取成不一樣的bundles,實現按需加載或並行加載。使用得當的話能很大的提高加載效率。一般有三種代碼拆方式:

  • Entry Points: 經過entry的配置來手動拆分代碼。
  • Prevent Duplication: 使用插件SplitChunksPlugin來刪除重複代碼和拆分代碼。
  • Dynamic Imports: 經過模塊內的內聯函數調用來拆分代碼。

webpack4.6.0+版本增長了對預加載和預獲取的支持:

  • prefetch:未來某些導航可能須要資源
  • preload:當前導航期間可能須要資源

在webpack4+中,推薦使用SplitChunksPlugin來分離代碼,這個插件容許咱們將共同的依賴提取到一個現有的塊或者一個全新的塊中去。相較於以前使用的CommonsChunkPlugin插件(webpack4+已廢棄),webpack在SplitChunksPlugin中作了更多的優化,在基於如下的條件時新的代碼塊會被自動建立:

  • 新的代碼塊被共享或者來自node_modules文件夾
  • 新的代碼塊大於30kb(在min+giz以前)
  • 按需加載代碼塊的請求數量應該<=5
  • 頁面初始化時加載代碼塊的請求數量應該<=3

同時SplitChunksPlugin提供了豐富的api供咱們實現個性化設置,咱們能夠根據本身的項目特性來設置如何分離代碼塊。詳情查詢

SplitChunksPlugin配置以下:

module.exports = {
        //...
        optimization: {
            splitChunks: {
                chunks: 'async',
                minSize: 30000,
                maxSize: 0,
                minChunks: 1,
                maxAsyncRequests: 5,
                maxInitialRequests: 3,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: {
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        }
};
複製代碼

該插件支持咱們配置緩存組來緩存不一樣的文件,經過test配置來選擇什麼樣的模塊能夠進入該緩存組。

// 該名爲vendors的緩存組能夠緩存全部來自node_modules的文件
splitChunks: {
    cacheGroups: {
        commons: {
            test: /[\\/]node_modules[\\/]/,
            name: "vendors",
            chunks: "all"
        }
    }
}
// 注意:這可能會致使下載額外的代碼。
// 實際應用中應該只包含核心功能和框架,避免包過於龐大。
複製代碼

環境

webpack4中對於區分開發和生產環境的不一樣提出了兩種解決方案:webpack-merge和env環境變量。

webpack-merge

安裝了webpack-merge之後,咱們須要修改本來的webpack.config.js

- webpack.config.js
   + webpack.common.js
   + webpack.dev.js
   + webpack.prod.js
複製代碼

webpack.common.js是設置entry, output等通用設置和開發環境、生產環境都能使用的插件的配置文件。 webpack.dev.js須要設置mode爲development,表示這是開發環境,一樣咱們的devtool(使用強效source-map),devServer也是配置在這個文件,咱們能夠在這個文件中作一些針對本身項目開發需求的個性化配置。 webpack.prod.js設置mode爲production,表示生產環境,此時webpack4默認啓用插件TerserPlugin,咱們能夠將壓縮文件的插件、針對生產環境的一些優化措施放置在裏面。

環境變量

webpack的環境變量跟操做系統的環境變量是不一樣的,webpack容許咱們傳入任意數量的環境變量,經過命令行--env傳入。可是若要使用該環境變量,須要將module.exports變爲函數,將環境變量以參數的形式傳入。

// webpack.config.js
const path = require('path');

module.exports = env => {
  // 使用你的環境變量
  console.log('NODE_ENV: ', env.NODE_ENV);
  console.log('Production: ', env.production);

  return {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
};
複製代碼

經過這樣,咱們即可以區分出不一樣的環境須要的不一樣的配置。

拓展

HappyPack

webpack容許運行在node.js中,因爲它是單線程模型,所以不能並行處理多個任務,Happy Pack將任務分解給多個子進程去併發執行,子進程處理完成後再將結果發送給主進程,所以能實現讓webpack同時處理多個任務,減小構建時間。

const HappyPack = require('happypack');

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                // 將對.js文件的處理轉交給id爲babel的HappyPack的實列
                use: ['happypack/loader?id=babel'],
                exclude: path.resolve(__dirname, 'node_modules') // 排除文件
            }
        ]
    },
    plugins: [
    /**** 使用HappyPack實例化 *****/
        new HappyPack({
            // 用惟一的標識符id來表明當前的HappyPack 處理一類特定的文件
            id: 'babel',
            // 處理文件,用法和Loader配置是同樣的
            loaders: ['babel-loader']
        })
    ]
}
複製代碼

在loader中,將對文件的處理都傳遞給happypack/loader,利用id做爲標識符。而後在plugin插件中新增HappyPack實例,告訴HappyPack須要作的事情。 HappyPack是爲了解決webpack在node中單線程執行構建速度慢而存在的一個插件,可以顯著的提升webpack的構建速度。

總結

在開發環境中,咱們更注重的是如何及時快速的將更新的代碼展現在網頁上,如何快速定位錯誤,所以webpack提供了強效source-map和模塊熱更新的機制來幫助開發人員。在生產環境中,咱們須要的是如何讓代碼包更小、構建更迅速,所以有了輕量級source-map,css代碼壓縮工具,tree shaking配和js壓縮工具等等,都是爲了讓最後打包出來的代碼體量更小。 一樣在項目較爲複雜的時候也須要將代碼進行分包處理,使用異步加載,進一步提升用戶使用時的加載速度,一樣爲了彌補webpack在node中也是單線程加載的緣由,還提供了HappyPack,使得webpack可以並行加載。

相關文章
相關標籤/搜索