1. 程式人生 > >webpack4.x深入與實踐

webpack4.x深入與實踐

一、什麼是webpack

是一個前端資源載入/打包工具。它將根據模組的依賴關係進行靜態分析,然後將這些模組按照指定的規則生成對應的靜態資源。它做的事情是,分析你的專案結構,找到JavaScript模組以及其它的一些瀏覽器不能直接執行的拓展語言(Scss,TypeScript等),並將其轉換和打包為合適的格式供瀏覽器使用。可以將多種靜態資源 js、css、less 轉換成一個靜態檔案,減少了頁面的請求。

二、安裝和命令列

1、新建一個目錄,進入目錄,初始化


2、安裝

全域性安裝

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ npm install webpack -g

在輸出版本時,顯示,要安裝webpack-cli

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack -v
The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI.
-> When using npm: npm install webpack-cli -D
-> When using yarn: yarn add webpack-cli -D
$ npm install webpack-cli -g

這樣就能輸出版本,可以看到我安裝的是4.2.0,這裡要注意,自webpack4之後,使用有很大的變化

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack -v
4.2.0

區域性安裝

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ cnpm install webpack webpack-cli --save-dev

(1)練習():處理js檔案,在專案根目錄下,新建hello.js,然後打包

$ webpack hello.js hello.bundle.js
Hash: e4a6ea308e8987e8d082
Version: webpack 4.2.0
Time: 556ms
Built at: 2018-3-27 11:35:19
 1 asset
Entrypoint main = main.js
   [0] ./hello.js 40 bytes {0} [built]
   [1] multi ./hello.js hello.bundle.js 40 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.

ERROR in multi ./hello.js hello.bundle.js
Module not found: Error: Can't resolve 'hello.bundle.js' in 'E:\workspace\xampp\htdocs\text\webpackText'
 @ multi ./hello.js hello.bundle.js

顯示沒有配置webpack的mode選項,預設有production和development兩種,我們輸入

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development
Hash: f28182541f5f8d1a0d8e
Version: webpack 4.2.0
Time: 62ms
Built at: 2018-3-27 11:42:01

ERROR in Entry module not found: Error: Can't resolve './src' in 'E:\workspace\xampp\htdocs\text\webpackText'

依然有錯:未找到入口模組發成錯誤,

這是因為webpack4.x是以專案根目錄下的./src/index.js作為入口,所以我們要新建src目錄且改hello.js為index.js

這裡還要注意:

webpack4.x的打包已經不能用webpack 檔案a 檔案b的方式,而是直接執行webpack --mode development或者webpack --mode production,這樣便會預設進行打包,入口檔案是'./src/index.js',輸出路徑是'./dist/main.js',其中src目錄即index.js檔案需要手動建立,而dist目錄及main.js會自動生成。 

因此我們不再按webpack 檔案a 檔案b的方式執行webpack指令,而是直接執行

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development
Hash: 34a98f4253e13bf8f430
Version: webpack 4.2.0
Time: 108ms
Built at: 2018-3-27 11:47:52
  Asset      Size  Chunks             Chunk Names
main.js  2.85 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/index.js] 40 bytes {main} [built]

這樣便能實現打包。

每次這樣寫是不是都點麻煩,我們可以在package.json中

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development"
  },

每次執行就可以:

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ npm run dev            // == webpack --mode development

(2)練習:處理css檔案

新建一個css檔案style.css,在index.js中引入


然後打包:

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development
ERROR in ./src/style.css
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type.

會報如上錯誤,是因為webpack不支援css檔案型別,需要依賴loader

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ npm install css-loader style-loader --save-dev

css-loader:使webpack可以處理css檔案

style-loader:新建一個style標籤,把css-loader處理過的檔案放進去,然後插入到HTML標籤中

安裝之後使用(直接在檔案前):

或者(在命令列):

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development --module-bind 'css=style-loader!css-loader'         // 給css繫結。。。。

那每次更新都要執行一次,有沒有自動更新的???

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development --module-bind 'css=style-loader!css-loader' --watch      // watch引數監聽,每次儲存檔案會自動執行

(3)其他引數:

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/webpackText
$ webpack --mode development --module-bind 'css=style-loader!css-loader' --progress --display-modules --display-reasons

--progerss:會出現打包過程,有百分比進度條

--display-modules:會把所有打包的模組列出來

--display-reasons:會把打包的原因列出來

三、webpack的配置

(1)新建一個專案並初始化

[email protected] MINGW64 /
$  cd e:/workspace/xampp/htdocs/text/demo/webpack-demo
$ npm init
$ cnpm install webpack webpack-cli --save-dev

(2)新建一個檔案webpack.config.js(預設名),是在使用webpack時預設的配置檔案

單檔案輸入:

const path = require('path');

module.exports = {
	entry: './src/js/main.js',                                // 入口檔案
	output: {                                                 // 出口檔案
		path: path.resolve(__dirname, 'dist/js'),         // 出口檔案位置,一定要是絕對路徑
		filename: 'bundle.js'                             // 出口檔名
	}
}

上面:將會打包。。。main.js檔案到。。。bundle.js檔案

多檔案輸入:

const path = require('path');

module.exports = {
	entry: {
		main: './src/js/main.js',   // 入口檔案
		a: './src/js/a.js'
	},
	output: {            // 出口檔案          
		path: path.resolve(__dirname, 'dist/js'),         // 出口檔案位置
		filename: '[name].js'      // 出口檔名,name就是entry的鍵名
	}
}

四、自動生成HTML頁面檔案

(1)安裝html-webpack-plugin外掛

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install html-webpack-plugin --save-dev

(2)在webpack配置package.config.js中

const path = require('path');
var htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
	entry: {
		main: './src/js/main.js',   // 入口檔案
		a: './src/js/a.js'
	},
	output: {            // 出口檔案          
		path: path.resolve(__dirname, 'dist'),         // 出口檔案位置
		filename: 'js/[name].js'      // 出口檔名
	},
	plugins: [
		new htmlWebpackPlugin({
			filename: '[name]-[hash].html',         // 生成的HTML名,路徑為上面output中的path
			template: './index.html',               // 會與根目錄下的index.html相關聯,把根目錄下index的東西都放到生成的HTML中
			inject: 'head'                          // 打包後的script放到head中
		})
	]
}

(3)傳參使用

1、引數

plugins: [
		new htmlWebpackPlugin({
			filename: 'index.html',
			template: './index.html',
			title: 'hello world'
		})
	]
在根目錄下的index.html中
<h2><%= htmlWebpackPlugin.options.title %></h2>

生成的dist/index.html中

<h2>hello world</h2>

2、上線地址

output: {            // 出口檔案          
		path: path.resolve(__dirname, 'dist'),         // 出口檔案位置
		filename: 'js/[name].js',      // 出口檔名,
		publicPath: 'http://cdn.com/'    // 上線的地址
	},

在生成的index.html中

<script type="text/javascript" src="http://cdn.com/js/main.js"></script>
<script type="text/javascript" src="http://cdn.com/js/a.js"></script>

3、html壓縮

title: 'hello world',
minify: {
    removeComments: true,        // 去掉註釋
    collapseWhitespace: true     // 去掉空格
}

4、多頁面應用,生成多個html檔案

new htmlWebpackPlugin({
	filename: 'main.html',
	template: './index.html',
	title: 'hello world',
	chunks: ['main', 'a']     // 會引入main.js和a.js
}),
new htmlWebpackPlugin({
	filename: 'a.html',
	template: './index.html',
	title: 'hello world',
	excludeChunks: ['main']    // 會引入除main以外的js
})

五、loader的配置

1、解析es6語法

(1)安裝babel

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install babel-loader babel-core babel-preset-env --save-dev

(2)配置webpack

module: {
    rules: [
{
test: /\.js$/,               // 匹配js檔案
loader: 'babel-loader',
exclude: path.resolve(__dirname, 'node_modules'),    // 匹配時忽略這個目錄,提高打包速度
include: path.resolve(__dirname, 'src'),             // 匹配時查詢的範圍
query: {
presets: ['env']
} 
}
]
},

2、解析css

(1)安裝style-loader和css-loader

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install style-loader css-loader --save-dev

(2)配置webpack

{
	test: /\.css$/,
	loader: 'style-loader!css-loader'           // 從右到左執行,所以注意順序
}

(3)在專案中經常有類似-webkit的字首,每次寫很麻煩,這裡就要用到postcss-loader,後處理loader

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install postcss-loader autoprefixer --save-dev                                      // autoprefixer是自動補全

配置webpack

{
	test: /\.css$/,
	use: [
		'style-loader',                                                // 注意順序
		{ loader: 'css-loader', options: { importLoaders: 1 } },       // 在css中使用@import引入其他檔案時,
		'postcss-loader'                                               // 不加importLoaders,postcss-loader不會操作引入的檔案
	]
}

新建一個postcss.config.js檔案和webpack.config.js同級

module.exports = {
	plugins: [
		require('autoprefixer')
	]
}

此時,如果你打包,並不會報錯,但是字首可能也沒有,所以需要在package.json中加入

"browserslist": [
    "> 1%",                                // 全球瀏覽器使用率大於1%,最新兩個版本並且是IE8以上的瀏覽器,加字首
    "last 2 versions",
    "not ie <= 8"
  ]

3、解析less

(1)安裝

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install less less-loader --save-dev

(2)webpack的配置

{
	test: /\.less$/,
	loader: 'style-loader!css-loader!postcss-loader!less-loader'     // 不用加importLoader,less-loader預設會有
}
4、解析sass

sass的使用和less一樣,只要把less改為sass就行了

5、處理html模板檔案

(1)安裝html-loader

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install html-loader --save-dev

(2)配置

{
	test: /\.html$/,
	loader: 'html-loader'
}

(3)使用

layer.js

import tpl from './layer.html';
import './layer.less';

function layer () {
	return {
		name: 'layer',
		tpl: tpl
	}
}

export default layer;

app.js

import Layer from './components/layer/layer.js';
import './css/common.css';

const App = function () {
	var app = document.getElementById('app');
	var layer = new Layer();
	app.innerHTML = layer.tpl;
}

App();

6、使用ejs模板檔案,字尾為tpl或ejs

(1)安裝

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install ejs-loader --save-dev

(2)配置

{
	test: /\.tpl$/,
	loader: 'ejs-loader'
}

(3)使用

layer.tpl

<div class="layer">
	<div>this is <%= name %></div>
	<% for (var i=0; i<arr.length; i++) { %> 
		<%= arr[i] %>
	<% } %>
</div>

layer.js

import './layer.less';
import tpl from './layer.tpl';            // 返回是一個函式

function layer () {
	return {
		name: 'layer',
		tpl: tpl
	}
}

export default layer;

app.js

import Layer from './components/layer/layer.js';
import './css/common.css';

const App = function () {
	var app = document.getElementById('app');
	var layer = new Layer();
	app.innerHTML = layer.tpl({
		name: 'xueer',
		arr: ['apple', 'oppo', 'xiaomi']
	});
}

App();

7、用file-loader處理圖片

(1)安裝

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install file-loader --save-dev

(2)配置

{
	test: /\.(png|jpg|gif|svg)$/i,
	loader: 'file-loader'
}

(3)使用

layer.less

.layer {
	width: 600px;
	height: 200px;
	background: url('../../assets/1.png');
	div {
		width: 400px;
		height: 100px;
		background: red;
	}
	.flex {
		display: flex;
	}
}

若是在.tpl或.ejs中使用

<img src="${ require('../../assets/1.png') }">

(4)也可以加引數

{
	test: /\.(png|jpg|gif|svg)$/i,
	loader: 'file-loader',
	query: {
		name: 'assets/[name]-[hash:5].[ext]'
	}
}

8、使用url-loader處理圖片(會影響檔案大小)

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install url-loader --save-dev
{
	test: /\.(png|jpg|gif|svg)$/i,
	loader: 'url-loader',
	query: {
		limit: 30000,                     // 當圖片小於30kb的時候,圖片變為base64位,不打包
		name: 'assets/[name]-[hash:5].[ext]'
	}
}

9、通過image-webpack-loader和url-loader結合:先有image-webpack-loader打包,在通過url-loader

[email protected] MINGW64 /e/workspace/xampp/htdocs/text/demo/webpack-demo
$ cnpm install image-webpack-loader --save-dev
{
	test: /\.(png|jpg|gif|svg)$/i,
	loaders: [
		'url-loader?limit=1000&name=assets/[name]-[hash:5].[ext]',
		'image-webpack-loader'
	]
}