webpack4發佈已經有一段時間了,我在實踐的過程當中發現,不少項目配置在webpack3下工做正常,可是升級到webpack4直接就崩了,若是想要webpack4正常工做,不少插件也須要升級到新版。下面是我使用webpack4配置的一個學習案例,包含了平常開發的經常使用配置項,好比多入口文件配置、模板文件自定義、版本號控制、js和css分離、css自動添加前綴、scss轉css、圖片及字體文件的處理、babel編譯JS語法和API等等javascript
當咱們修改代碼後,須要從新打包文件,這時候爲了不瀏覽器緩存,每每須要爲文件添加一個版本號css
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
plugins: [
new HtmlWebpackPlugin({
inject:'body', // 插入位置
favicon: './favicon.ico', // icon圖標
title: 'webpack learn', // 生成的html文件的標題
filename: 'index.html', // 生成的html文件名稱
minify:{
removeComments: false, // 刪除註釋
collapseWhitespace: false // 刪除空格
}
})
]
}
複製代碼
打包後的代碼html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webpack learn</title>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body>
<script type="text/javascript" src="main.js?f8f60ca3f6ee44382620"></script></body>
</html>
複製代碼
html-webpack-plugin這個插件會生成一個名爲index.html、標題是webpack learn
的文件,而且自動把打包後的文件插入到html中。若是不配置這個插件,filename的默認值就是index.html
,title默認是Webpack APP
java
inject表示插入的位置,默認是body
,可選值head
favicon表示能夠添加一個icon圖標 minify表示對壓縮文件,removeComments和collapseWhitespace的默認值都是falsenode
html-webpack-plugin插件可使用模板文件,這樣咱們就能夠自定義一個html文件,而後讓這個插件把打包後的文件自動插入到模板文件中jquery
tmp/tmp.html模板文件webpack
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>template file</title>
<body>
<div>hello template</div>
</html>
複製代碼
插件配置項git
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './tmp/tmp.html'
})
]
複製代碼
打包後生成的index.htmlgithub
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>template file</title>
<body>
<div>hello template</div>
</html>
<script type="text/javascript" src="main.js?b321307e65d6b0fbee0b"></script>
複製代碼
對於多頁面通常會對應多個入口文件,不一樣的html頁面輸出對應不一樣的入口文件,html-webpack-plugin插件支持配置多頁面。多頁面須要配置chunks和excludeChunks,chunks表示所包含的入口文件,excludeChunks表示要排除的入口文件web
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
a: './src/main-a.js',
b: './src/main-b.js',
c: './src/main-c.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'a.html',
template: './tmp/tmp.html',
chunks: ['a'] // 加載a對應的打包文件
}),
new HtmlWebpackPlugin({
filename: 'b.html',
template: './tmp/tmp.html',
chunks: ['b'] // // 加載b對應的打包文件
}),
new HtmlWebpackPlugin({
filename: 'c.html',
template: './tmp/tmp.html',
excludeChunks: ['a', 'b'] // 加載非a、b對應的打包文件
})
]
}
複製代碼
運行結果
<!-- a.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webpack learn</title>
<body>
<div>hello template</div>
</html>
<script type="text/javascript" src="a.js?82a9a04389852053c167"></script>
<!-- b.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webpack learn</title>
<body>
<div>hello template</div>
</html>
<script type="text/javascript" src="b.js?82a9a04389852053c167"></script>
<!-- c.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webpack learn</title>
<body>
<div>hello template</div>
</html>
<script type="text/javascript" src="c.js?82a9a04389852053c167"></script>
複製代碼
除了以連接的形式引入入口文件,也能夠內聯到頁面中。html-webpack-inline-source-plugin插件專門用來處理入口文件內聯的
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
plugins: [
new HtmlWebpackPlugin({
inlineSource: '.(js|css)$' // 全部的js和css文件內聯引入
}),
new HtmlWebpackInlineSourcePlugin()
]
}
複製代碼
babel能夠把es最新標準的代碼轉爲es5代碼,首先須要安裝babel-core核心程序,及babel-loader
npm i babel-loader babel-core -D
複製代碼
因爲ES每一年會發佈一個新版本,因此在進行轉換時,須要選擇從哪一個標準進行轉換,可供選擇的有'es2015'、'es2016'、'es2017'、'latest'、'env'等多個不一樣的標準。
babel-preset-env標準是使用最多的,babel-preset-env在沒有任何配置選項的狀況下,與 babel-preset-latest(或者babel-preset-es2015,babel-preset-es2016和babel-preset-es2017一塊兒)的行爲徹底相同
npm i babel-preset-env -D
複製代碼
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
module: {
rules:[{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env'],
cacheDirectory: true
}
}
}]
}
}
複製代碼
rules屬性中配置的exclude表示node_modules
文件夾不須要babel進行轉換。也能夠配置一個include選項,好比include: path.resolve(__dirname, 'src')
,表示只有src文件夾中的文件須要轉換
cacheDirectory選項的默認值是false,設置爲true將緩存 loader 的執行結果,加快編譯速度
babel默認只轉換JavaScript語法,對於新的API,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等是不會轉換的。若是須要轉換API,須要使用babel-polyfill,babel-polyfill是一個全局墊片
npm i babel-polyfill -D
複製代碼
入口文件引入babel-polyfill
// main.js
import 'babel-polyfill';
let set = new Set([1,2,3]);
複製代碼
babel-polyfill是一個全局墊片,開發中更經常使用的是babel-plugin-transform-runtime這個局部墊片,由於它可使包的體積更小
npm i babel-plugin-transform-runtime babel-runtime -D
複製代碼
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
module: {
rules:[{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env'],
cacheDirectory: true,
plugins: ['transform-runtime']
}
}
}]
}
}
複製代碼
處理css會用到css-loader和style-loader,css-loader用於讀取並加載css文件,style-loader將它插入到頁面中
// main.js
require('./assets/styles/cssdemo.css');
複製代碼
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
module: {
rules:[{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
},
plugins: [
new HtmlWebpackPlugin({})
]
}
複製代碼
因爲各大瀏覽器對CSS兼容性不一樣,部分CSS特性須要加上瀏覽器前綴才能正常工做,postcss-loader能夠幫咱們自動完成加前綴的工做
npm i postcss-loader autoprefixer postcss-import -D
複製代碼
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', {
loader: 'css-loader',
options: { importLoaders: 1 }
},
{
loader: 'postcss-loader',
options: {
plugins: [
require('postcss-import'), // 解決css中import其餘css
require('autoprefixer')
]
}
}
]
}]
}
複製代碼
須要安裝sass-loader及node-sass。
npm i sass-loader node-sass -D
複製代碼
module: {
rules: [{
test: /\.scss$/,
use: ['style-loader','css-loader',
{
loader: 'postcss-loader',
options: { plugins: [require('autoprefixer')] }
},
'sass-loader'
]
}]
}
複製代碼
默認狀況下,CSS會被打包到入口JS文件中。若是須要把CSS分離出來,須要使用extract-text-webpack-plugin插件
npm i extract-text-webpack-plugin@next -D
複製代碼
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js?[hash]'
},
module: {
rules: [{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader',
{
loader: 'postcss-loader',
options: { plugins: [require('autoprefixer')] }
},
'sass-loader'
]
})
}]
},
plugins: [
new HtmlWebpackPlugin({}),
new ExtractTextPlugin('main.css')
]
}
複製代碼
webpack處理圖片、字體、音樂、視頻等資源時,須要安裝file-loader
npm i file-loader -D
複製代碼
// main.js
require('./assets/styles/cssdemo.css');
複製代碼
/* cssdemo.css */
body {
background: url('../images/dog.jpg') no-repeat;
}
h1 {
color: red;
}
複製代碼
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}, {
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpe?g|gif|svg)(\?\S*)?$/,
loader: 'file-loader',
query: {
name: '[name].[ext]?[hash]'
}
}
]
}
複製代碼
若是是在html模板中,經過img標籤引入圖片,須要使用${require('')}
將相對路徑包裹一次
<img src="${require('../src/images/dog.jpg')}" alt="">
複製代碼
好比說咱們經過npm安裝了jQuery,只須要經過provide-plugin插件就能夠自動加載模塊,而沒必要處處 import 或 require
npm i provide-plugin -D
複製代碼
var ProvidePlugin = require('provide-plugin');
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
複製代碼
在項目中使用
console.log($('#box'), jQuery('#box'))
複製代碼
若是是把jQuery保存到了本地,能夠經過設置別名來引用
resolve:{
alias:{
jQuery$: path.resolve(__dirname,'src/libs/jquery.min.js')
}
}
複製代碼
最後基於上面的全部介紹,把全部的配置綜合到一塊兒。因爲代碼比較多,就再也不這裏展開了,我把示例代碼放到了GitHub