原文轉載於 www.rails365.netjavascript
原文: A tale of Webpack 4 and how to finally configure it in the right waycss
開始新的項目html
mkdir webpack-4-tutorial
cd webpack-4-tutorial
npm init
複製代碼
上下會初始化一個項目,接下來添加webpack4.java
npm install webpack webpack-cli --save-dev
複製代碼
肯定裝的webpack版本是4.node
接下來修改package.jsonwebpack
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack"
},
複製代碼
保存以後,npm run dev
會出現一個錯誤.git
Insufficient number of arguments or no entry found.
Alternatively, run 'webpack(-cli) --help' for usage info.
Hash: 4442e3d9b2e071bd19f6
Version: webpack 4.12.0
Time: 62ms
Built at: 2018-06-22 14:44:34
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
ERROR in Entry module not found: Error: Can't resolve './src' in '~/workspace/webpack-4-tutorial'
複製代碼
兩個問題,第一個出錯的意思是說,沒有設置mode
,默認會認爲是production
模式。第二個是說src
下沒有找到入口模塊。es6
咱們來改下,再次打開package.json
github
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development"
},
複製代碼
在項目下新建src
文件夾,而後src
下新建index.js
.web
console.log(「hello, world」);
複製代碼
保存後再次運行npm run dev
.
這時候成功打包,發現項目裏多了一個dist
文件夾. 這是由於webpack4是號稱0配置,因此不少東西都給你配置好了,好比默認的入口文件,默認的輸出文件。 在webpack中配置環境,基本都是兩個配置文件(development
, production
).在webpack4
中,有這兩個模式來區分。
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
複製代碼
保存後運行npm run build
,你會發現main.js
文件小了不少。
上面不少東西都是經過默認配置來的,嘗試去重寫配置,在不使用配置文件的狀況下。
"scripts": {
"dev": "webpack --mode development ./src/index.js --output ./dist/main.js",
"build": "webpack --mode production ./src/index.js --output ./dist/main.js"
},
複製代碼
es6
就是將來,但是如今的瀏覽器對他的支持不是很好,咱們須要babel
來轉換他。
npm install babel-core babel-loader babel-preset-env --save-dev
複製代碼
bable的配置,須要建立一個文件去配置。 新建.babelrc
文件,寫入以下內容
{
"presets": [
"env"
]
}
複製代碼
接下來須要配置babel-loader
,能夠在package.json
文件配置,可是仍是獨立出去好,比較好維護。項目下新建一個webpack.config.js
.加入一些基礎配置。
// webpack v4
const path = require('path');
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
複製代碼
而後package.json
的腳本能夠去除一些配置.
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
複製代碼
而後再運行編譯,也是能夠正常編譯。
在dist
文件夾下新建一個index.html
的文件.
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>Hello, world!</div>
<script src="main.js"></script>
</body>
</html>
複製代碼
上面這段代碼,使用到了style.css
. 接來下去處理css
的問題. src
文件夾下新建style.css
。
div {
color: red;
}
複製代碼
而後在js文件中引入css.,打開index.js
文件
import "./style.css";
console.log("hello, world");
複製代碼
解析來咱們就須要配置css
的規則,打開webpack.config.js
// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //新加入
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{
fallback: 'style-loader',
use: ['css-loader']
})
}// 新加的css 規則
]
}
};
複製代碼
上面咱們用了一些插件和加載器.須要去安裝.
npm install extract-text-webpack-plugin --save-dev
npm install style-loader css-loader --save-dev
複製代碼
上面咱們提出css來編譯,你能夠看到他的規則, 規則能夠這樣認爲
{
test: /\.拓展名$/,
exclude: /不須要執行的文件夾/,
use: {
loader: "你的加載器"
}
}
複製代碼
咱們須要extract-text-webpack-plugin
這個提取插件,由於webpack
只會辨別js
.這裏須要經過ExtractTextPlugin
獲取css文本進行壓縮。
咱們再次嘗試編譯,npm run dev
發現會有報錯,這個是由於這個提取器在新版本的緣由。相關報錯Webpack 4 compatibility 能夠解決這個問題,那就是換個版本。
npm install -D extract-text-webpack-plugin@next
複製代碼
而後再編譯,發現能夠來,同時再dist
下有一個style.css文件。
這時候package.json
的依賴文件以下
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"style-loader": "^0.20.3",
"webpack": "^4.4.1",
"webpack-cli": "^2.0.12"
}
複製代碼
下面咱們來配置支持scss
npm install node-sass sass-loader --save-dev
複製代碼
咱們在src
下新建一個index.html
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>Hello, world!</div>
<script src="main.js"></script>
</body>
</html>
複製代碼
安裝html
插件
npm install html-webpack-plugin --save-dev
複製代碼
安裝完成以後來修改webpack.config.js
// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 新加
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{
fallback: 'style-loader',
use: ['css-loader']
})
}// 新加
]
},
plugins: [
new ExtractTextPlugin({filename: 'style.css'}),
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
})// 新加
]
};
複製代碼
這個是最終的html的一個模版. 如今html
,css
,js
基本配置的差很少,咱們刪除dist
來試試。
rm -rf dist/
npm run dev
複製代碼
這時候會發現dist
下存在js,css,html
文件.
能夠查看關於hash緩存的文檔來使瀏覽器只請求改變的文件.
webpack4提供了chunkhash來處理。
來看看:
// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 新加
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js' //changed
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{
fallback: 'style-loader',
use: ['css-loader']
})
}// 新加
]
},
plugins: [
new ExtractTextPlugin(
{filename: 'style.[chunkhash].css', disable: false, allChunks: true}
), //changed
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
})
]
};
複製代碼
而後src
下的html
也要修改
<html>
<head>
<link rel="stylesheet" href="<%=htmlWebpackPlugin.files.chunks.main.css %>">
</head>
<body>
<div>Hello, world!</div>
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
</body>
</html>
複製代碼
能夠發現這裏改變來,這個是使模版使用hash.
好了,如今能夠編譯,會發現dist
下的css和js名字是帶有hash指的。
若是咱們改變代碼,在編譯的時候,發現並無生成創新的hash名文件。
div {
color: 'red';
background-color: 'blue';
}
複製代碼
再次進行編譯npm run dev
,發現並無生產新的hash文件名稱,可是若是改變js代碼,再次編譯,會發現是改變了hash名稱
import "./index.css"
console.log('Hello, world!');
複製代碼
如何解決?
兩種辦法:
npm install webpack-md5-hash --save-dev
// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash'); //新加
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{
fallback: 'style-loader',
use: ['css-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin(
{filename: 'style.[hash].css', disable: false, allChunks: true}
),//changed
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
}),
new WebpackMd5Hash() //新加
]
};
複製代碼
而後編譯查看是否改變。 如今的變化是,改變css文件,那麼css文件的hash名字改變。若是改變js文件,那麼css和js的壓縮hash名稱都將改變。
方法1可能還會存在其餘的衝突,因此來嘗試下mini-css-extract-plugin
這個插件是爲了取代extract-plugin, 並帶來兼容性的改變
npm install --save-dev mini-css-extract-plugin
嘗試使用
// webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//新加
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
// {
// test: /\.css$/,
// use: ExtractTextPlugin.extract(
// {
// fallback: 'style-loader',
// use: ['css-loader']
// })
// }
{
test: /\.(scss|css)$/,
use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
} // 新加
]
},
plugins: [
// new ExtractTextPlugin(
// {filename: 'style.[hash].css', disable: false, allChunks: true}
// ),
new MiniCssExtractPlugin({
filename: 'style.[contenthash].css',
}),//新加
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
}),
new WebpackMd5Hash()
]
};
複製代碼
好了,接下來咱們嘗試改變文件會怎麼變化。 改變css,進行編譯發現只有css的文件改變來。改變js文件,發現編譯以後只有js的hash名稱改變,不錯,就是這樣。
postcss你們應該不會陌生了。
npm install postcss-loader --save-dev
npm i -D autoprefixer
複製代碼
-D.
建立postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
複製代碼
而後來配置你的webpack.config.js
// webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(scss|css)$/,
use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']//changed
}
]
},
plugins: [
// new ExtractTextPlugin(
// {filename: 'style.[hash].css', disable: false, allChunks: true}
// ),
new MiniCssExtractPlugin({
filename: 'style.[contenthash].css',
}),
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
}),
new WebpackMd5Hash()
]
};
複製代碼
這裏使用clean-webpack-plugin
插件.
npm i clean-webpack-plugin --save-dev
// webpack v4
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');//新加
module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(scss|css)$/,
use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']//changed
}
]
},
plugins: [
// new ExtractTextPlugin(
// {filename: 'style.[hash].css', disable: false, allChunks: true}
// ),
new CleanWebpackPlugin('dist', {} ),//新加
new MiniCssExtractPlugin({
filename: 'style.[contenthash].css',
}),
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
}),
new WebpackMd5Hash()
]
};
複製代碼
這樣每次編譯的時候,就會清空dist
文件夾