從零配置webpack 4+react腳手架(二)

前言:

可前往個人Github/blog進行閱讀,如有幫助,賞個star😊javascript

你可能也注意到了,html文件中的關於js的引用是咱們手動寫的,那假如咱們改了輸出路徑或打包編譯以後的文件名,那咱們豈不是還要手動去修改html文件中的引用?咱們怎麼作到,像create-react-app中那樣一旦你修改了某個文件內容,頁面會本身刷新?咱們來一步一步實現它們,固然,這一小節不只僅只是爲了完成這兩點。css

自動編譯html並引入js文件

public的index.html應該自動編譯到dist目錄,而且全部的js引用是自動添加的。你可使用html-webpack-plugin插件來處理這個優化。html

安裝HtmlWebpackPlugin

在控制檯執行如下代碼:java

npm install --save-dev html-webpack-plugin
複製代碼

在webpack.prod.config.js中配置plugins屬性

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      // 這裏有小夥伴可能會疑惑爲何不是 '../public/index.html'
      // 個人理解是不管與要用的template是否是在一個目錄,都是從根路徑開始查找
      template: 'public/index.html',
      inject: 'body',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
      },
    })
  ]
});
複製代碼
  • filename:打包以後的html文件名字
  • template:以咱們本身定義的html爲模板生成,否則咱們還要到打包以後的html文件中寫
  • inject:在body最底部引入js文件,若是是head,就是在head中引入js
  • minify:壓縮html文件,更多配置點我
    • removeComments:去除註釋
    • collapseWhitespace:去除空格

更多配置請點擊官方READMEnode

刪除index.html中手動引入的script標籤

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>從零配置webpack4+react腳手架</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
複製代碼

如今咱們再來打包試試,看看dist中是否是多出了html文件,而且自動引入了script,用瀏覽器打開它試試看是否是能正確輸出內容了!react

給打包出的js文件換個不肯定名字

這個操做是爲了防止由於瀏覽器緩存帶來的業務代碼更新,而頁面卻沒變化的問題,你想一想看,假如客戶端請求js文件的時候發現名字是同樣的,那麼它頗有可能不發新的數據包,而直接用以前緩存的文件,固然,這和緩存策略有關。webpack

那咱們怎麼給導出文件的安排一個不肯定的名字呢?很簡單,[hash]或[chunkhash]
修改webpck.prod.config.jsgit

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  output: {
    filename: 'js/[name].[chunkhash:8].bundle.js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'public/index.html',
      inject: 'body',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
      },
    })
  ]
});
複製代碼

其中,name就是模塊名稱,咱們在entry中進行過配置,在這裏從新設置會代替以前common中的設置,chunkhash是文件內容的hash,webpack默認採用md5的方式對文件進行hash。8是hash的長度,若是不設置,webpack會設置默認值爲20。github

如今你從新打包,去看看生成的js文件的名字~web

打包編譯前清理dist目錄

在上面的修改後,由於js文件名字不一樣,你以後再打包,會把以前打包以後的js文件也留下,咱們只想要最新打包編譯的文件,就須要先清除dist目錄,再從新生成。

安裝clean-webpack-plugin

npm install --save-dev clean-webpack-plugin
複製代碼

這個插件不被官方文檔所收錄,能夠去github查看它的配置文檔

使用clean-webpack-plugin

修改webpck.prod.config.js

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  output: {
    filename: 'js/[name].[chunkhash:8].bundle.js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'public/index.html',
      inject: 'body',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
      },
    }),
    new CleanWebpackPlugin()
  ]
});
複製代碼

這裏須要注意:以前引入CleanWebpackPlugin的寫法是
const CleanWebpackPlugin = require('clean-webpack-plugin'); 
並且在下面new的時候須要傳入參數,dist文件路徑。可是如今必須這樣引入:
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
並且,不用再寫路徑參數

如今再來執行看看,是否是隻有一個js文件了!~

代碼分割

咱們先看下,咱們以前打包編譯的時候,控制檯的信息:

image.png

咱們看到,這個打包以後的bundle.js文件大小爲129kb,隨着業務代碼愈來愈多,這個包會變得愈來愈大,你每次修改了代碼併發布,用戶都須要從新下載這個包,可是想一想看,咱們修改的代碼只是整個代碼的一小部分,還有許多其餘不變的代碼,例如 react 和 react-dom ,那咱們把這部分不變的代碼單獨打包。

修改 webpack.common.config.js ,增長一個入口:

entry: {
    index: './src/index.js',
    framework: ['react','react-dom'],
  },
複製代碼

從新打包,發現react和react-dom 被編譯成framework.js,可是咱們的index.bundle.js仍是129kb,沒有變過。
這是由於咱們尚未抽離index.js中的公共代碼。

webpack3版本是經過配置CommonsChunkPlugin插件來抽離公共的模塊。webpack4版本,官方廢棄了CommonsChunkPlugin,而是改用配置optimization.splitChunks的方式,更加方便。

添加代碼至 webpack.prod.config.js :

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      cacheGroups: {
        framework: {
          test: "framework",
          name: "framework",
          enforce: true
        },
        vendors: {
          priority: -10,
          test: /node_modules/,
          name: "vendor",
          enforce: true,
        },
      }
    }
  },
  //...
};
複製代碼

cacheGroups對象,定義了須要被抽離的模塊,其中test屬性是比較關鍵的一個值,他能夠是一個字符串,也能夠是正則表達式,還能夠是函數。若是定義的是字符串,會匹配入口模塊名稱,會從其餘模塊中把包含這個模塊的抽離出來。name是抽離後生成的名字,和入口文件模塊名稱相同,這樣抽離出來的新生成的framework模塊會覆蓋被抽離的framework模塊,雖然他們都叫framework。
vendors這個緩存組,它的test設置爲 /node_modules/ 表示只篩選從node_modules文件夾下引入的模塊,因此全部第三方模塊纔會被拆分出來。

從新打包,咱們發現index.bundle.js文件大小隻有:1.69kb

image.png

咱們隨意修改一下app.js中的內容,好比

import React from 'react';

function App() {
  return (
    <div className="App"> <h1>I am changed</h1> </div>
  );
}

export default App;
複製代碼

再打包一次,你會發現index.bundle.js(不被緩存)的hash值變了,可是freamework.bundle.js(能被緩存)的hash值沒變,成了成了!!

壓縮JS文件

咱們須要把打包生成的js文件儘量壓縮,以便減小文件體積,更快地被用戶加載。
咱們須要一個插件: uglifyjs-webpack-plugin 來作這份工做

安裝uglifyjs-webpack-plugin

在控制檯執行如下代碼:

npm install uglifyjs-webpack-plugin --save-dev
複製代碼

引入uglifyjs-webpack-plugin

增長以下代碼至 webpack.prod.config.js :

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
複製代碼

optimization內配置minimizer參數

minimizer: [
  new UglifyJsPlugin(),
	//...
],
複製代碼

如今optimization參數應該是如今這樣:

optimization: {
    minimizer: [new UglifyJsPlugin()],
    splitChunks: {
      chunks: 'all',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      cacheGroups: {
        framework: {
          priority: 100,
          test: "framework",
          name: "framework",
          enforce: true
        },
        vendors: {
          priority: -10,
          test: /node_modules/,
          name: "vendor",
          enforce: true,
        },
      }
    }
  },
複製代碼

從新打包編譯看看~咱們的index.bundle.js減小了0.1kb,固然,隨着業務代碼愈來愈多,這部分差距會漸漸變大。

自動編譯打包

咱們每次修改代碼,查看結果都要經歷以此 npm run build ,大大下降了開發效率,這難以忍受!
webpack給咱們提供了devServer開發環境,支持熱更新,至關舒服。

安裝webpack-dev-server

在控制檯執行如下代碼:

npm install webpack-dev-server --save-dev
複製代碼

增長代碼至 webpack.dev.config.js :

是否是都快忘記這個以前建立的配置文件了?不要緊,反正也沒代碼,它是專門用來配置咱們開發環境的

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

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'development',
  output: {
    filename: 'js/[name].[hash:8].bundle.js',
  },
  devServer: {
    contentBase: path.resolve(__dirname, '../dist'),
    open: true,
    port: 9000,
    compress: true,
    hot: true
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      inject: 'body',
      hash: false
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
});
複製代碼

HotModuleReplacementPlugin是webpack熱更新的插件,設置devServer.hot爲true,而且在plugins中引入HotModuleReplacementPlugin插件便可。
還須要注意的是咱們開啓了hot,那麼導出不能使用chunkhash,須要替換爲hash。

修改咱們的package.json

像以前build的時候,咱們是經過配置package.json作到的,如今咱們一樣加入如下代碼來模擬:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config ./config/webpack.prod.config.js",
+ "start": "webpack-dev-server --inline --config ./config/webpack.dev.config.js"
  },
複製代碼

接下來,在控制檯執行

npm run start
複製代碼

是否是自動開了一個端口爲9000的網頁,上面是咱們寫的頁面內容,這和咱們的配置都是一一對應的。
如今你隨意修改app.js中的代碼,再回到頁面看下是否是也跟着變了,那咱們就整合webpack-dev-server成功!

下面一小節咱們會配置css相關的屬性,加油!

相關文章
相關標籤/搜索