[Webpack] 核心概念、基礎配置、經常使用loader和經常使用插件

Webpack 是一個JavaScript應用程序的打包模塊化工具.Webpack裏一切文件都是模塊,處理應用程序時,它會遞歸構建程序中各個模塊的依賴關係圖, 最後將這些模塊打包成一個或者多個bundlecss

核心概念

入口(enrty)

入口起點指示 webpack 應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。html

出口(output)

output 屬性告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件,默認值爲 ./dist。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。能夠經過在配置中指定一個 output 字段,來配置這些處理過程。node

loader

loade 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後就能夠利用 webpack 的打包能力,對它們進行處理。本質上,webpack loader 將全部類型的文件,轉換爲應用程序的依賴圖(和最終的 bundle)能夠直接引用的模塊。react

插件(plugins)

loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務。webpack

模式

經過選擇 developmentproduction 之中的一個,來設置 mode 參數,能夠啓用相應模式下的 webpack 內置的優化。web

基礎配置

能夠經過一個JavaScript文件導出Webpack的配置:typescript

module.exports = {
  mode: "development",	// 模式
  entry: {},	// 入口
  output: {},	// 輸出
  resolve: {},	// 解析
  module: {},	// 模塊
  plugins: [],	// 插件
}
複製代碼

mode

mode的取值有developmentproduction。經過設置mode,webpack在打包時會使用相應模式的內置優化,並process.env.NODE_ENV設置爲對應的值。json

entry

entry是應用的入口,能夠傳入一個字符串、數組或者對象。若是傳入一個字符串或字符串數組,chunk 會被命名爲 main。若是傳入一個對象,則每一個鍵(key)會是 chunk 的名稱,該值描述了 chunk 的入口起點。api

module.exports = {
    // ...
    entry: {
        app: "./src/index.js"
    }
}
複製代碼

output

output 能夠控制 webpack 如何向硬盤寫入編譯文件。即便能夠存在多個入口起點,但只指定一個輸出配置。數組

  • output.path: 指定打包後內容的輸出目錄

  • output.filename: 配置每一個輸出bundle的名稱,可使用模板字符串配置輸出。

    模板 描述
    [hash] 模塊標識符的hash
    [chunkhash] chunk內容的hash
    [name] 模塊名稱
    [id] 模塊標識符
    [query] 模塊的query
  • output.chunkFilename:配置非入口chunk文件的名稱,默認[id].js,與filename選項一致可使用模板字符串。

  • output.publicPath:指定在瀏覽器中所引用的此輸出目錄對應的公開 URL

module.export = {
    // ...
    output: {
        path: "./dist",
        publicPath: "https://example.com",
        filename: "[name].[chunkhash].js",
        chunkFilename:  "[name].[chunkhash].js"
    }
}
複製代碼

resolve

resolve設置模塊如何被解析。

  • resolve.alias:設置導入模塊時的別名
  • resolve.modules:設置模塊解析時搜索的目錄
module.exports = {
    // ...
    resolve: {
        alias: {
            "@src": "./src/"
        },
        modules: ["./node_modules"]
    }
}
複製代碼

module

module設置webpack如何處理不一樣類型的模塊。

  • module.rules:配置規則數組。在建立模塊時,匹配對應的規則並應用loader處理模塊。

規則(Rule)的配置:

  • rule.test:匹配模塊文件路徑
  • rule.include:匹配目錄下的文件
  • rule.exclude:匹配不在目錄下的文件
  • rule.use:使用loaderloader應用順序爲從右到左
module.exports = {
    // ...
    rules: [{
        test: /.js$/,
        include: ['./src'],
        use: ["babel-loader"]
    }]
}
複製代碼

plugins

plugins設置打包過程當中使用的插件。

module.exports = {
    // ...
    plugins: []
}
複製代碼

devtool

設置source maps如何生成,開發時能夠將此選項設置爲cheap-module-eval-source-map

module.exports = {
    // ...
    devtool: "cheap-module-eval-source-map"
}
複製代碼

devServer

設置webpack-dev-server使用時的選項,能夠配置監聽端口、代理等。

const path = require("path")
module.exports = {
    // ...
    devServer: {
        host: "0.0.0.0",
        contentBase: path.resolve(__dirname, "build"),
		hot: true,	// 開啓模塊熱替換
		historyApiFallback: true,  // 使用index.html頁面來代替404響應,使用HTML5 History API時可將該選項設置爲true,例如react-router
		proxy: {
            '/api': 'http://127.0.0.1:3000'
        }
    }
}
複製代碼

經常使用loader

CSS相關

用於解析CSSloader通常有:style-loadercss-loaderpostcss-loaderless-loadersass-loader

  • style-loader:經過注入<style>標籤將CSS添加到DOM
  • css-loader:解釋@importurl(),會 import/require() 後再解析它們。css-loader前應用了loader須要指定importLoaders選項
  • postcss-loader:應用postcss
  • less-loader:解析less
  • sass-loader:解析sass
module.exports = {
    // ...
    module: {
        rules: [{
            test: /.less$/,
            include: ["./src"],
            use: [
                "style-loader",
                {
                    loader: "css-loader",
                    options: {
                        importLoaders: 2
                    }
                },
                "postcss-loader",
                "less-loader"
            ]
        }]
    }
}
複製代碼

JavaScript相關

  • babel-loaderbabel-loader基於babel,用於解析JavaScript文件。babel有豐富的預設和插件,babel的配置能夠直接寫到options裏或者單獨寫道配置文件裏。

幾個babel經常使用的預設和插件:

  • @babel/preset-env:用於轉換最新的JavaScript代碼、爲低版本瀏覽器提供polyfill
  • @babel/preset-react:用於解析jsx內容,該預設包含了@babel/plugin-syntax-jsx@babel/plugin-transform-react-jsx@babel/plugin-transform-react-display-name三個插件。當指定了development選項時,還額外包含@babel/plugin-transform-react-jsx-self@babel/plugin-transform-react-jsx-source兩個插件
  • @babel/preset-typescript:用於解析typescript內容,該預設僅包含@babel/plugin-transform-typescript插件。在解析typescript內容時,該預設會直接把typescript相關的內容去掉
  • @babel/plugin-proposal-class-properties:用於解析類屬性的插件
  • @babel/plugin-proposal-object-rest-spread:用於解析析構對象的插件
  • @babel/plugin-transform-runtime:用於複用babel內置的helper代碼從而減少代碼體積

babel經常使用的預設有preset-envpreset-reactpreset

module.export = {
    // ...
    module: {
        rules: [{
            test: /.js$/,
            include: ["./src/"],
            use: [{
                loader: "babel-loader",
                options: {
                    presets: [
                       "@babel/preset-env",
                        "@babel/preset-react",
                        "@babel/preset-typescript",
                    ],
                    plugins: [
                        "@babel/plugin-proposal-class-properties",
   						 "@babel/plugin-proposal-object-rest-spread",
                    ]
                }
            }]
        }]
    }
}
複製代碼

其餘資源

除了CSSJavaScript資源外,項目裏還有其餘的資源,例如圖片、字體等。對於這類資源,能夠經過file-loaderurl-loader解析。

  • file-loader:告訴Webpack引用的模塊是一個文件,並返回其打包後的url
  • url-loader:做用與file-loader相似,但當文件大小(單位 byte)低於指定的限制時,能夠返回一個 DataURL。
module.exports = {
    // ...
    module: {
        rules: [{
        	test: /\.(png|jpg|gif)$/,
        	use: [{
            	loader: 'url-loader',
            	options: {
              		limit: 8192
            	}
          	}]
        }]
    }
}
複製代碼

經常使用插件

copy-webpack-plugin

copy-webpack-plugin用於打包時複製文件。

const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
    // ...
    plugins: [
        new CopyWebpackPlugin({
        	{
        		from: "./public",
        		to: "./build/"
      		}
        })
    ]
} 
複製代碼

html-webpack-plugin

生成一個 HTML5 文件,包括使用 script 標籤的 body 中的全部 webpack 包。

const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
	// ...
	plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html",
      		chunks: ["app"]
        })
    ]
};
複製代碼

add-asset-html-webpack-plugin

插入一個JavaScript或者CSS資源到html-webpack-plugin生產的html頁面中。使用DLL時,能夠經過該插件將生成的JavaScript文件插入到頁面中。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const path = require("path")
module.exports = {
	// ...
	plugins: [
		new HtmlWebpackPlugin(),
		new AddAssetHtmlPlugin({
            filepath: path.resolve(__dirname, './dlls/*.dll.js'),
      		outputPath: "dlls",
      		publicPath: "/dlls"
        })
    ]
};
複製代碼

clean-webpack-plugin

clean-webpack-plugin能夠清理文件,能夠用於打包時清理以前打包的文件。

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
	// ...
	plugins: [
		new CleanWebpackPlugin()
    ]
};
複製代碼

mini-css-extract-plugin

將CSS提取到單獨的文件中,爲每一個包含CSS的JS文件建立一個CSS文件,同時該插件支持CSS和SourceMap的按需加載。使用該插件時,style-loader須要替換爲該插件提供的loader

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
	// ...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,	// 須要替換 style-loader
					{
						loader: "css-loader",
						options: {
							importLoaders: 1
						}
					}
				]
            }
        ]
    },
	plugins: [
		new MiniCssExtractPlugin({
			filename: "static/css/[name].[chunkhash:8].css",
			chunkFilename: "static/css/[name].[chunkhash:8].chunk.css"
		})
    ]
};
複製代碼

webpack.HotModuleReplacementPlugin

模塊熱替換插件,開啓HMR。能夠和webpack.NamedModulesPlugin搭配使用,顯示模塊的相對路徑,建議用於開發環境。

const webpack = require('webpack');
module.exports = {
	// ...
	plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
    ]
};
複製代碼

webpack.DefinePlugin

建立一個在編譯時能夠配置的全局常量。

const webpack = require('webpack');
module.exports = {
	// ...
	plugins: [
        new webpack.DefinePlugin({
            VERSION: JSON.stringify("0.0.1")
        })
    ]
};
複製代碼

由於這個插件直接執行文本替換,給定的值必須包含字符串自己內的實際引號。一般,有兩種方式來達到這個效果,使用'"production"', 或者使用 JSON.stringify('production')

webpack.DllPluginwebpack.DllReferencePlugin

DllPlugin和DllReferencePlugin提供了一種拆分包的方法,能夠極大地提升構建時間性能。

// 製做dll
const webpack = require("webpack");
const path = require("path");

module.exports = {
	mode: "production",
	entry: {
        react: ["react", "react-dom"],
        antd: ["antd"],
        utils: ["lodash", "moment"]
    },
    output: {
		path: "./dlls",
		filename: "[name].dll.js",
		library: "[name]_[hash]"
	},
	resolve: {
		extensions: [".js", ".jsx"],
		modules: ["./node_modules"]
	},
	plugins: [
		new webpack.DllPlugin({
			path: path.resolve(__dirname, "./dlls/[name].manifest.json"),
			name: "[name]_[hash]"
		})
	]
};
複製代碼
// 使用dll
const webpack = require("webpack");
const path = require("path");

module.exports = {
	// ...
	plugins: [
		new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/react.manifest.json"),
		}),
        new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/antd.manifest.json"),
		}),
        new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/utils.manifest.json"),
		}),
		new AddAssetHtmlWebpackPlugin({
			filepath: path.resolves(__dirname,  './dlls/*.dll.js'),
			outputPath: "dlls",
			publicPath: "/dlls"
		})
	]
};
複製代碼
相關文章
相關標籤/搜索