wepack is a module bundle:模塊打包工具。javascript
模塊:不限於js文件,CSS文件,圖片等等。css
ES Module CommonJs AMD CMDhtml
安裝方式:java
全局 npm install webpack webpack-cli -g
node
項目中安裝 (推薦)react
npm install webpack webpack-cli --save-dev
webpack
npm install webpack webpack-cli -D
git
解決:npx webpack -ves6
npx命令會去當前項目目錄的node-modules尋找webpack
github
初始化 npm init -y
(自動生成默認配置項)
npm info webpack
(查看包的版本號)
npm install
下載全部依賴包
注:不建議安裝在全局。不一樣兩個項目,若是webpack版本號不同,一個3,一個4,其中一個運行不起來
npx webpack index.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"
}
}
複製代碼
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
命令
npm install -g moduleName
命令
npm install -save moduleName
命令
npm install -save-dev moduleName
命令
總結 devDependencies 節點下的模塊是咱們在開發時須要用的,好比項目中使用的 gulp ,壓縮css、js的模塊。這些模塊在咱們的項目部署後是不須要的,因此咱們可使用 -save-dev 的形式安裝。像 express 這些模塊是項目運行必備的,應該安裝在 dependencies 節點下,因此咱們應該使用 -save 的形式安裝。
webpack默認打包js文件,不認識CSS文件或者圖片文件等等。
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請求數目,提高網 頁加載速度
}
}
}
]
}
複製代碼
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'
]
}
複製代碼
{
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
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目錄中的全部文件都將被刪除一次,目錄自己不會
],
複製代碼
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文件中
//todo............
複製代碼
// 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會將打包好的文件存到電腦的內存中,提高打包速度。
需求:
當須要樣式局部刷新不影響頁面其餘內容
const webpack = require('webpack');
devServer: {
contentBase: './dist',
open: true,
port: 8081,
hot: true, //開啓HMR
hotOnly: true //當HMR沒有起做用,也不用刷新頁面
}
new webpack.HotModuleReplacementPlugin()
複製代碼
當須要修改js文件而不影響其餘的內容
if(module.hot) {
module.hot.accept('./demo', function () {
demo()
document.body.removeChild(document.getElementById('asd'))
})
}
複製代碼
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'] //還須要一個配置項
}
}
複製代碼
需求:有些低版本的瀏覽器不兼容一些方法,變量等,如promise
,map
。須要藉助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 參數說明:
優化
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'
}
}]]
}
}
複製代碼
注意:以上方式是寫業務代碼時使用的。當開發類庫,組件庫時若是使用這種方式會將好比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
文件
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"] //若是不配置沒法使用箭頭函數
}
複製代碼
只支持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的文件
}
複製代碼
寫兩套代碼
{
"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)
複製代碼
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'*/
這個能夠給打包的文件起名字
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中保存,在作判斷是放入哪一個組裏
//異步代碼不用
複製代碼
import
語法
每個打包出來的文件都是一個chunk
webpack --profile --json > stats.json
github.com/webpack/ana…
代碼分析
瀏覽器查看代碼使用率:network + ctrl + shift + p
webpack推薦多使用 異步加載的代碼 import().then()
利用緩存提高頁面性能是很是有限的,利用webpack的懶加載 + prefetch 極大的提高代碼利用率,是很是好的提高頁面性能的方案。
某些異步加載的代碼,當首頁徹底加載出來後,此時帶寬徹底釋放後,能夠進行預加載。
prefetch
prefetch和preload的區別:
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....