webpack4學習筆記分享

webpack 4

webpack到底是什麼


wepack is a module bundle:模塊打包工具。javascript

模塊:不限於js文件,CSS文件,圖片等等。css

ES Module CommonJs AMD CMDhtml

安裝方式:java

  1. 全局 npm install webpack webpack-cli -gnode

  2. 項目中安裝 (推薦)react

    1. npm install webpack webpack-cli --save-devwebpack

    2. npm install webpack webpack-cli -Dgit

      解決npx webpack -ves6

      npx命令會去當前項目目錄的node-modules尋找webpackgithub

    3. 初始化 npm init -y(自動生成默認配置項)

    4. npm info webpack(查看包的版本號)

    5. npm install 下載全部依賴包

注:不建議安裝在全局。不一樣兩個項目,若是webpack版本號不同,一個3,一個4,其中一個運行不起來

使用webpack的配置文件


  • 沒有配置文件時會有默認的配置,但必須指定文件名:npx webpack index.js
  • webpack.config.js(默認) 可使用 npx webpack --config mywebpackconfig.js
const path = require('path')
module.exports = {
    mode: 'production(壓縮代碼)/development(不壓縮代碼)' //默認production
    entry: {
    	main: './src/index.js'
	},
    output: {
        filename: '[name].js',   //佔位符
        path: path.resolve(__dirname, 'bundle'),  //絕對路徑
        publicPath: "http://baidu.com"    //添加前綴地址
    }
}
複製代碼
  • process.cwd():是當前執行node命令時候的文件夾地址 ——工做目錄,保證了文件在不一樣的目錄下執行時,路徑始終不變
  • __dirname:是被執行的js 文件的地址 ——文件所在目錄
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "bundle": "webpack"   //在scripts中直接運行webpack,默認如今當前目錄中找,至關於 npx webpack,
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.39.0",
    "webpack-cli": "^3.3.6"
  }
}

複製代碼

淺談webpack打包輸出內容


Hash: 714f926a0d1129251086
Version: webpack 4.39.0
Time: 683ms
Built at: 2019-08-02 15:52:43
  Asset      Size  Chunks /*打包的文件的id值*/            Chunk Names、/*打包的文件的名字,配置文件中entry配置的文件名 */
main.js  1.17 KiB       0  [emitted]  main
Entrypoint main = main.js
[0] ./index.js + 2 modules 480 bytes {0} [built]
    | ./index.js 100 bytes [built]
    | ./Header.js 190 bytes [built]
    | ./Footer.js 190 bytes [built]

複製代碼

npm install moduleName命令

  1. 安裝模塊到項目node_modules目錄下。
  2. 不會將模塊依賴寫入devDependencies或dependencies 節點。
  3. 運行 npm install 初始化項目時不會下載模塊。

npm install -g moduleName命令

  1. 安裝模塊到全局,不會在項目node_modules目錄中保存模塊包。
  2. 不會將模塊依賴寫入devDependencies或dependencies 節點。
  3. 運行 npm install 初始化項目時不會下載模塊。

npm install -save moduleName命令

  1. 安裝模塊到項目node_modules目錄下。
  2. 會將模塊依賴寫入dependencies 節點。
  3. 運行 npm install 初始化項目時,會將模塊下載到項目目錄下。
  4. 運行npm install --production或者註明NODE_ENV變量值爲production時,會自動下載模塊到node_modules目錄中。

npm install -save-dev moduleName命令

  1. 安裝模塊到項目node_modules目錄下。
  2. 會將模塊依賴寫入devDependencies 節點。
  3. 運行 npm install 初始化項目時,會將模塊下載到項目目錄下。
  4. 運行npm install --production或者註明NODE_ENV變量值爲production時,不會自動下載模塊到node_modules目錄中。

總結 devDependencies 節點下的模塊是咱們在開發時須要用的,好比項目中使用的 gulp ,壓縮css、js的模塊。這些模塊在咱們的項目部署後是不須要的,因此咱們可使用 -save-dev 的形式安裝。像 express 這些模塊是項目運行必備的,應該安裝在 dependencies 節點下,因此咱們應該使用 -save 的形式安裝。

loader是什麼


webpack默認打包js文件,不認識CSS文件或者圖片文件等等。

loader:打包的方案

使用Loader打包靜態資源(圖片篇)


file-loader

module: {
		rules: [
			{
				test: /\.(jpg|png|gif)$/,
				use: {
					loader: 'file-loader',
					options: {
                        //placeholder
						outputPath: 'images/',
						name: '[name]_[hash].[ext]'
					}
				}
			}
		]
	}
複製代碼

url-loader

Name 類型 默認 描述
limit number undefined 限制文件大小
mimetype string extanme 指定文件的mimetype(不然從文件拓展名推斷)
fallback string file-loader loader文件大於限制時,指定loader打包文件

將圖片以base64的形式打包在js文件裏。

limit :限制圖片大小,若是小於這個值,打包成base64,大於這個值,和file-loader同樣。

module: {
		rules: [
			{
				test: /\.(jpg|png|gif)$/,
				use: {
					loader: 'url-loader',
					options: {
                        //placeholder
						outputPath: 'images/',
						name: '[name]_[hash].[ext]',
						limit: 2048    //限制小於2048(2kb)打包成base64的形式。不然以圖片的形式打包到 bundle目錄下。 好處是:能夠減小一些小圖片的http請求數目,提高網 頁加載速度
					}
				}
			}
		]
	}
複製代碼

使用Loader打包靜態資源(樣式篇)


  • style-loader:將樣式以style標籤的形式,寫在html文件的head中。

  • css-loader:將樣式文件分析合併,打包。

  • sass-loader:將scss文件翻譯成css。

  • postcss-loader:能夠自動加廠商前綴 -webkit

    • 新建postcss.conifg.js

    • npm i -D autoprefixer

      module.exports = {
           plugins : [
               require('autoprefixer')({
                   overrideBrowserslist : ['last 2 versions']      //必須設置支持的瀏覽器纔會自動添加添 加瀏覽器兼容
               })
           ]
       };
      複製代碼

loader的使用順序是從下到上:

{
				test: /\.(css|less|scss)$/,
				use: [
				'style-loader', 
				'css-loader', 
				'sass-loader', 
				'postcss-loader'
				]
			}
複製代碼
若是要給某個loader增長配置項
{
				test: /\.(css|less|scss)$/,
				use: [
				'style-loader', 
                   {
                       loader: 'css-loader',
                       options: {
                           importLoaders: 2   //目錄文件中經過import引入的文件,可能不會走sass-loader和 postcss-loader ,這個配置項爲了讓import引入的css文件,再過2個loader。 
                       }
                   }, 
				'sass-loader', 
				'postcss-loader'
				]
			}
複製代碼

CSS Module (CSS模塊化)

{
				test: /\.(css|less|scss)$/,
				use: [
				'style-loader', 
                   {
                       loader: 'css-loader',
                       options: {
                           importLoaders: 2,
                           modules: true   //CSS Module
                       }
                   }, 
				'sass-loader', 
				'postcss-loader'
				]
			}

複製代碼
import style from './style.scss';
img.classList.add(style.a);   //不一樣文件添加不一樣的樣式

複製代碼

webpack打包字體文件

file-loader

使用plugins讓打包更方便


plugin能夠在webpack運行到某一個時刻的時候,幫你作一些事情。(相似生命週期函數)

html-webpack-plugin 會在打包結束後,自動生成一個html文件,並把打包生成的js自動引入到這個html文件中。

const htmlWebpackPlugin = require('html-webpack-plugin');
    plugins: [
      new htmlWebpackPlugin({
		  template: "./src/index.html"  //默認不會生成 <div id="dom2"></div> 須要模板
	  })
    ],

複製代碼

clean-webpack-plugin 會在打包以前,刪除以前打包過的文件。

const htmlWebpackPlugin = require('html-webpack-plugin');
	const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    plugins: [
      new htmlWebpackPlugin({
		  template: "./src/index.html"
	  }),
      new CleanWebpackPlugin() //打包以前 webpack的output.path目錄中的全部文件都將被刪除一次,目錄自己不會
    ],

複製代碼

SourceMap的配置


1565448633280

mode: 'development';
devtool: 'cheap-module-eval-source-map';
//
mode: 'production';
devtool: 'cheap-module-source-map'

複製代碼

​ source-map 生成一個map.js的文件

​ inline 將map.js文件注入到打包好的js文件

​ cheap:精確到多少行,而不關心多少列 ;不關心loader的錯誤;

​ module 不加module只關心本身的文件 不關心第三方文件 loader的錯誤映射

​ eval 以eval的形式注入到打包好的js文件中

  • source-map的原理
//todo............

複製代碼

使用webpack-dev-server提高開發效率


連接

// npm i webpack-dev-server -D
	devServer: {
		contentBase: './dist',	//路徑
		open: true,	//打開瀏覽器
		proxy: {	//代理轉發 跨域
		    './api': {
		    	target: 'http://localhost:3000'
			}
        },
		port: 8081	//修改默認端口
	}
	//===========================
	 "scripts": {
    	"bundle": "webpack",
   		"start": "webpack-dev-server"
  	}

複製代碼

能夠結合node.js webpackmiddleware 寫一個本身的webpack-dev-server

webpack-dev-server會將打包好的文件存到電腦的內存中,提高打包速度。

熱模塊替換(Hot Module Replacement)


需求:

  • 當須要樣式局部刷新不影響頁面其餘內容

    1565544822334

    1565544722994

    const webpack = require('webpack');
    devServer: {
    		contentBase: './dist',
    		open: true,
    		port: 8081,
        	hot: true,   //開啓HMR
        	hotOnly: true  //當HMR沒有起做用,也不用刷新頁面
    	}
    new webpack.HotModuleReplacementPlugin()
    
    複製代碼
  • 當須要修改js文件而不影響其餘的內容

    • CSS一樣的配置代碼不會生效,須要額外配置
    if(module.hot) {
      module.hot.accept('./demo', function () {
        demo()
        document.body.removeChild(document.getElementById('asd'))
      })
    }
    
    複製代碼

使用Babel處理ES6語法


npm install --save-dev babel-loader @babel/core @babel/core是babel的核心語法庫 (這個loader只是將webpack和babel作了鏈接,並不會處理js文件,須要藉助其餘模塊)

npm install @babel/preset-env --save-dev

@babel/preset-env包含了全部es6-es5的規則。

{
	test: /\.js$/,
	exclude: /node-modules/,   //exclude意思是在node-modules中的js文件不會去操做
	loader: 'babel-loader',
    options: {
        presets: ['@babel/preset-env']      //還須要一個配置項
    }
}

複製代碼

需求:有些低版本的瀏覽器不兼容一些方法,變量等,如promisemap。須要藉助babel-polyfill/core-js作一個補充。

npm install @babel/polyfill已經淘汰

最新npm install core-js@3

業務代碼中引入import '@babel/polyfill'/import 'core-js'

可是這麼作會引入不少用不着的,如今想按需引入

這裏講一講 useBuiltIns 配置

咱們可能在全局引入 babel-polyfill,這樣打包後的整個文件體積必然是會變大的。

可是經過設置 "useBuiltIns": "usage" 可以把 babel-polyfill 中你須要用到的部分提取出來,不須要的去除。

useBuiltIns 參數說明:

  1. false: 不對 polyfills 作任何操做
  2. entry: 根據 target 中瀏覽器版本的支持,將 polyfills 拆分引入,僅引入有瀏覽器不支持的 polyfill
  3. usage(新):檢測代碼中 ES6/7/8 等的使用狀況,僅僅加載代碼中用到的 polyfills

優化

import 'core-js'
	//入口文件引入
	{
        test: /\.js$/,
        exclude: /node-modules/,
        loader: 'babel-loader',
        options: {
          presets: [['@babel/preset-env', {
            useBuiltIns: 'entry',   //若是配置爲usage 就沒必要引入import 'core-js'
            corejs: 3,    //必須配置依賴的corejs
            targets: {
              chrome: '70'
            }
          }]]
        }
      }

複製代碼

img

注意:以上方式是寫業務代碼時使用的。當開發類庫,組件庫時若是使用這種方式會將好比promise注入到全局變量,污染全局變量

npm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime

注意:@babel/runtime as a production dependency

{
        test: /\.js$/,
        exclude: /node-modules/,
        loader: 'babel-loader',
        options: {
          'plugins': [['@babel/plugin-transform-runtime', {
              "absoluteRuntime": false,
        	  "corejs": 3,   //默認值false 是不會將ES6的語法打包的
        	  "helpers": true,
        	  "regenerator": true,
        	  "useESModules": false
          }]]
        }
      }

複製代碼
corejs option Install command
false npm install --save @babel/runtime
2 npm install --save @babel/runtime-corejs2
3 npm install --save @babel/runtime-corejs3

注意當文件過於複雜時:在根目錄下建立.babelrc文件

配置React代碼的打包


npm install @babel/preset-react

{
  "presets": [
    ["@babel/preset-env", {
      "useBuiltIns": "entry",
      "corejs": 3,
      "targets": {
        "chrome": "70"
      }}],
    ["@babel/preset-react"]     // presets 中的內容是從後往前一次執行的,先執行@babel/preset-react
  ]
    "plugins": ["@babel/plugin-proposal-class-properties"]  //若是不配置沒法使用箭頭函數
}

複製代碼

Tree Shaking概念詳解


只支持ES Module(靜態引入) require是動態引入 不支持!

按需引入某一模塊中所須要的代碼。

//好比一個文件內部暴露了兩個方法,我在另外一個文件中只須要引入其中一個,可是webpack默認兩個方法都會打包
mode: 'development' //默認沒有開啓Tree Shaking

//配置webpack.config.js,當mode爲production時,不用配置這一項
{
    optimization: {
        usedExports: true
    }
}
//配置package.json
{
    "sideEffects": ["*.css","core.js"]  或者 false   //過濾不須要Tree Shaking的文件
}

複製代碼

Development和Production模式的區分打包


  • sourcemap
  • 壓縮代碼

寫兩套代碼

{
 "scripts": {
 	"dev": "webpack-dev-server --config webpack-dev-js",
 	"build": "webpack --config webpack-pro-js"
 }
}

複製代碼

問題:

這樣帶來了一個問題就是兩個文件中有很是多的重複代碼。

解決:

新建文件夾webpack.common.js,使用webpack-merge

const merge = require('webpack-merge');
const common = require('./common')
const dev = {
	...
}
module.exports = merge(common, dev)

複製代碼

Webpack和Code Splitting


optimization: {
	  splitChunks: {
       	chunks: "all",
        cacheGroups: {
            vendors: false, //前綴名
            default: false   
        }
    }
  },    // 同步代碼分割 webpack.config.js的配置項

複製代碼
function getComponent() {           //異步加載 代碼分割 經過dynamic import
  return import(/*webpackChunkName: 'lodash'*/'lodash').then(({ default: _ }) => {
    return _
  })
}

getComponent().then( _ => {
  console.log(_.join(['a', 'b', 'c'], '%^'));
})

複製代碼
{
  "presets": [
    ["@babel/preset-env", {
      "useBuiltIns": "entry",
      "corejs": 3,
      "targets": {
        "chrome": "70"
      }}],
    "@babel/preset-react"
  ],
  "plugins": ["@babel/plugin-syntax-dynamic-import"]   //使用插件
}

複製代碼

npm i -D @babel/plugin-syntax-dynamic-import`

/*webpackChunkName: 'lodash'*/ 這個能夠給打包的文件起名字

SplitChunksPlugin 配置參數詳解


Webpack和Code Splitting的底層就是是用了SplitChunksPlugin這個插件。

//SplitChunksPlugin 默認配置
splitChunks: {
    chunks: "async",    //只對異步代碼進行打包 可配置all(須要配置cacheGroups ) initial(同步)
    minSize: 30000,   //大於30kb作代碼分割
    minChunks: 1,	// 被用了至少多少次才進行代碼分割
    maxAsyncRequests: 5,  //同時加載的模塊數至多5個,超過5個,超過的不會作代碼分割了
    maxInitialRequests: 3,	//入口文件最大價值3個模塊,超過3個,超過的不會作代碼分割了
    automaticNameDelimiter: '~',  //組,文件鏈接符。
    name: true,
    cacheGroups: {
        vendors: {  //打包的文件屬於vendors這個組。
            test: /[\\/]node_modules[\\/]/,   //檢測須要打包的庫是否在node_modules中
            priority: -10,  //優先級 vendors大於default
            filename: 'vendors'  // ‘vendors.js’
        },
    	default: {	 //打包的文件屬於default這個組。
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true   //若是一個模塊被打包過 a,b,c c裏面引入了a,b a裏面又引入了b,則c直 接複用以前打包過的b,而不須要再次打包b
        }
    }
}
//同步代碼打包的過程當中,知足前面的配置要求,不會直接作代碼分割,而是放入cacheGroups中保存,在作判斷是放入哪一個組裏
//異步代碼不用

複製代碼

Lazy Loading懶加載,Chunk是什麼?


import語法

每個打包出來的文件都是一個chunk

打包分析,Preloading,Prefetching


webpack --profile --json > stats.json github.com/webpack/ana…

代碼分析

瀏覽器查看代碼使用率:network + ctrl + shift + p

webpack推薦多使用 異步加載的代碼 import().then()

利用緩存提高頁面性能是很是有限的,利用webpack的懶加載 + prefetch 極大的提高代碼利用率,是很是好的提高頁面性能的方案。

某些異步加載的代碼,當首頁徹底加載出來後,此時帶寬徹底釋放後,能夠進行預加載。

prefetch

1568643034126

prefetch和preload的區別:

  • prefetch會等主代碼徹底加載後帶寬空閒時加載;
  • preload會跟着主代碼一塊兒預加載。

CSS的代碼分割


entry: {
    main: './src/index.js'
}
output: {
    filename: "[name].js",    //main.js爲主文件入口,走的filename這個配置項;
    chunkFilename: "[name].chunk.js" //main.js中的按需加載的文件,走這個配置項。
}

複製代碼

css的代碼分割須要藉助插件:

MiniCssExtractPlugin 缺點:不支持HMR,適合線上環境作打包。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
use: [
    // 'style-loader',
    MiniCssExtractPlugin.loader,   //替換成這個。
    {
        loader: "css-loader",
        options: {
            importLoaders: 2
        }
    },
    'sass-loader',
    'postcss-loader'
    ]

複製代碼

optimize-css-assets-webpack-plugin 壓縮打包後的css代碼。

loading....

相關文章
相關標籤/搜索