webpack+react
https://juejin.im/post/5da5748851882555a8430641
本咸魚是根據(jù)這一篇博客來的的钞艇,同時我也記錄了一些我踩過的坑
建一個空文件夾 webpack-react
- 命令行執(zhí)行
npm init -y
// 生成一個package.json
// npm install就是根據(jù)這個文件去下載我們項目里使用的包
// 也就是配置項目所需的運行和開發(fā)環(huán)境。
之后我們安裝 webpack
npm i webpack webpack-cli -D
- 文件目錄
webpack-react
|- node_modules
|- package.json
接下來豪硅,我們在根目錄下新建一個文件夾名為 config 用于存放配置文件哩照,在此文件夾下創(chuàng)建一個 .js 文件名為 webpack.common.config.js ,敲入以下代碼:
// webpack 配置是標準的 Node.js的CommonJS 模塊懒浮,
const path = require('path');
module.exports = {
// 入口文件路徑
entry: {
app: './src/app.js',
},
// 出口文件
output: {
filename: 'js/bundle.js',
// dist 必須為絕對路徑
path: path.resolve(__dirname, '../dist')
publicPath:"/",
// 和后面dev配合使用飘弧,單頁面應(yīng)用路由
}
}
之后我們創(chuàng)建src文件,并在里面創(chuàng)建app.js
webpack-react-scaffold
+ |- config
+ |- webpack.common.config.js
|- node_modules
+ |- src
+ |- app.js
|- package.json
在package.json中配置
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 這里我們定義 --config 我們的webpack配置文件的路徑 默認是根目錄文件下的webpack.config.js文件,
// 為了代碼結(jié)構(gòu)清晰我們建立了config文件夾
// 并且我們知道為什么是 npm run build ,你不歡喜build,那么打包的命令可以start "start": "webpack --config ./config/webpack.common.config.js"
+ "build": "webpack --config ./config/webpack.common.config.js"
},
好了,我們試試怎么打包吧砚著。
在控制臺中輸入命令:
npm run build
執(zhí)行之后次伶,你會發(fā)現(xiàn)根目錄多出了一個文件夾: dist/js ,其中有一個js文件: bundle.js 稽穆,那么至此冠王,我們已經(jīng)成功編譯打包了一個js文件,即入口文件: app.js 舌镶。
使用webpack-merge
我們將使用一個名為 webpack-merge 的工具柱彻。通過"通用"配置豪娜,我們不必在環(huán)境特定(environment-specific)的配置中重復(fù)代碼。簡單來說就是生產(chǎn)環(huán)境不同哟楷,我們要給的配置也有所不同瘤载,但是可以共用一個共有的配置。
安裝
npm install --save-dev webpack-merge
之后我們在config中建立webpack.dev.config.js和webpack.prod.config.js
prod:生產(chǎn)環(huán)境 production
dev:開發(fā)環(huán)境 development
現(xiàn)目錄結(jié)構(gòu):
webpack-react-scaffold
|- config
|- webpack.common.config.js
+ |- webpack.prod.config.js
+ |- webpack.dev.config.js
|- node_modules
|- src
|- app.js
|- package.json
在webpack.prod.config.js里輸入代碼:
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
module.exports = merge(common, {
// 生產(chǎn)環(huán)境 可選production(默認)/ development / none
mode: 'production',
});
回到我們之前創(chuàng)建的 app.js 文件卖擅,輸入代碼:
var root =document.getElementById('root');
root.innerHTML = 'hello, webpack!';
在根目錄下創(chuàng)建一個文件夾名為: public 鸣奔,再新建一個html文件,名為: index.html 惩阶,以下內(nèi)容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>從零配置webpack4+react腳手架</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
html-webpack-plugin
index.html應(yīng)該自動編譯到dist目錄挎狸,并且所有的js引用是自動添加的。你可以使用html-webpack-plugin插件來處理這個優(yōu)化断楷。
npm install html-webpack-plugin -D
// -D是--save-dev的縮寫
在webpack.prod.config.js中配置plugins屬性
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
// 這里有小伙伴可能會疑惑為什么不是 '../public/index.html'
// 我的理解是無論與要用的template是不是在一個目錄伟叛,都是從根路徑開始查找
template: 'public/index.html',
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
},
})
]
});
- filename:打包之后的html文件名字
- template:以我們自己定義的html為模板生成,不然我們還要到打包之后的html文件中寫
- inject:在body最底部引入js文件脐嫂,如果是head,就是在head中引入js
- minify:壓縮html文件紊遵,更多配置點我
- removeComments:去除注釋
- collapseWhitespace:去除空格
現(xiàn)在我們再來打包試試账千,看看dist中是不是多出了html文件,并且自動引入了script暗膜,用瀏覽器打開它試試看是不是能正確輸出內(nèi)容了匀奏!
安裝react
npm install --save react react-dom
安裝完成之后,我們就可以寫react的JSX語法了学搜。
這里為了和react官方腳手架 create-react-app 的目錄結(jié)構(gòu)相類似娃善,我們在 src 文件夾下新建一個js文件, index.js 瑞佩,用于渲染根組件聚磺。index.js輸入:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
用jsx重寫app.js:
import React from 'react';
function App() {
return (
<div className="App">Hello World</div>
);
}
export default App;
并 webpack.common.config.js 文件中的入口進行修改,因為我們現(xiàn)在要編譯打包的應(yīng)該 index.js :
const path = require('path');
module.exports = {
entry: {
- app: './src/app.js',
+ index: './src/index.js',
},
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, '../dist')
}
}
現(xiàn)在嘗試一下重新運行 npm run build 炬丸,會發(fā)現(xiàn)打包失敗了瘫寝,為什么呢?接著看.....
因為webpack根本識別不了jsx語法稠炬,那怎么辦焕阿?使用loader對文件進行預(yù)處理。
其中首启,babel-loader暮屡,就是這樣一個預(yù)處理插件,它加載 ES2015+ 代碼毅桃,然后使用 Babel 轉(zhuǎn)譯為 ES5褒纲。那開始配置它吧准夷!
npm install --save-dev babel-loader @babel/preset-react @babel/preset-env @babel/core
- babel-loader:**使用Babel和webpack來轉(zhuǎn)譯JavaScript文件。
- @babel/preset-react:**轉(zhuǎn)譯react的JSX
- @babel/preset-env:**轉(zhuǎn)譯ES2015+的語法
- @babel/core:**babel的核心模塊
理論上我們可以直接在 webpack.common.config.js 中配置"options"外厂,但最好在當前根目錄冕象,注意,一定要是根目錄V=グ纭! 新建一個配置文件 .babelrc 配置相關(guān)的"presets":
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
// 大于相關(guān)瀏覽器版本無需用到 preset-env
"edge": 17,
"firefox": 60,
"chrome": 67,
"safari": 11.1
},
// 根據(jù)代碼邏輯中用到的 ES6+語法進行方法的導(dǎo)入掖棉,而不是全部導(dǎo)入
"useBuiltIns": "usage"
}
],
"@babel/preset-react"
]
}
再修改webpack.common.config.js
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
},
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, '../dist')
},
module: {
rules: [
{
//test 規(guī)定了作用于以規(guī)則中匹配到的后綴結(jié)尾的文件
test: /\.(js|jsx)$/,
// use使用什么插件
use: 'babel-loader',
// exclude 告訴我們不需要去轉(zhuǎn)譯"node_modules"這里面的文件墓律。
exclude: /node_modules/,
}
]
}
}
我們再次打包:
npm run build
我們再確認一次我們的目錄:
webpack-react-scaffold
|- config
|- webpack.common.config.js
|- webpack.prod.config.js
|- webpack.dev.config.js
|- node_modules
|- public
|- index.html
|- src
+ |- index.js
|- app.js
+ |- .babelrc
|- package.json
給打包出的js文件換個不確定名字
這個操作是為了防止因為瀏覽器緩存帶來的業(yè)務(wù)代碼更新,而頁面卻沒變化的問題幔亥,你想想看耻讽,假如客戶端請求js文件的時候發(fā)現(xiàn)名字是一樣的,那么它很有可能不發(fā)新的數(shù)據(jù)包帕棉,而直接用之前緩存的文件针肥,當然,這和緩存策略有關(guān)香伴。
很簡單慰枕,[hash]或[chunkhash],這里我們先使用hash
修改webpck.common.config.js:
const path = require('path')
module.exports = {
entry: {
index: "./src/index.js",
},
output: {
filename: "js/[name].bundle.[hash:4].js",
path: path.resolve(__dirname, "../dist")
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
}
],
},
}
name是 entry 的文件名 key,而不是文件名.
現(xiàn)在你重新打包,去看看生成的js文件的名字~
打包編譯前清理dist目錄
之前打包的dist里因為js文件名字不同已經(jīng)有了多個js文件,我們只想要最新打包編譯的文件即纲,就需要先清除dist目錄具帮,再重新生成。
安裝
npm i clean-webpack-plugin -D
修改webpack.prod.config.js:
const merge = require('webpack-merge')
const common = require('./webpack.common.config.js')
const HttpWebpackPlugin = require('http-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
// 這里有小伙伴可能會疑惑為什么不是 '../public/index.html'
// 我的理解是無論與要用的template是不是在一個目錄低斋,都是從根路徑開始查找
template: 'public/index.html',
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
},
}),
new CleanWebpackPlugin({
//現(xiàn)在已經(jīng)不需要再寫參數(shù)了,如果不起作用可以試試寫上參數(shù)
//cleanOnceBeforeBuildPatterns:[path.resolve(process.cwd(),"dist/*")]
})
]
});
現(xiàn)在試試應(yīng)該就只有一個js文件了
代碼分割
這個打包之后的bundle.js文件大小為129kb蜂厅,隨著業(yè)務(wù)代碼越來越多,這個包會變得越來越大膊畴,你每次修改了代碼并發(fā)布掘猿,用戶都需要重新下載這個包,但是想想看唇跨,我們修改的代碼只是整個代碼的一小部分术奖,還有許多其他不變的代碼,例如 react 和 react-dom 轻绞,那我們把這部分不變的代碼單獨打包采记。
修改 webpack.common.config.js ,增加一個入口:
entry: {
index: './src/index.js',
framework: ['react','react-dom'],
},
重新打包政勃,發(fā)現(xiàn)react和react-dom 被編譯成framework.js唧龄,但是我們的index.bundle.js還是129kb,沒有變過奸远。
這是因為我們還沒有抽離index.js中的公共代碼既棺。
webpack3版本是通過配置CommonsChunkPlugin插件來抽離公共的模塊讽挟。webpack4版本,官方廢棄了CommonsChunkPlugin丸冕,而是改用配置optimization.splitChunks的方式耽梅,更加方便。
添加代碼至 webpack.prod.config.js :
// 代碼太多就不重復(fù)了胖烛,根據(jù)上下文將代碼放在合適的地方
module.exports = merge(common,{
mode:"production",
plugins:[],
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
//cacheGroups對象眼姐,定義了需要被抽離的模塊
cacheGroups: {
framework: {
//test屬性是比較關(guān)鍵的一個值,他可以是一個字符串佩番,也可以是正則表達式众旗,還可以是函數(shù)。如果定義的是字符串趟畏,會匹配入口模塊名稱贡歧,會從其他模塊中把包含這個模塊的抽離出來。
test: "framework",
//name是抽離后生成的名字赋秀,和入口文件模塊名稱相同利朵,這樣抽離出來的新生成的framework模塊會覆蓋被抽離的framework模塊,雖然他們都叫framework猎莲。
name: "framework",
enforce: true
},
//vendors這個緩存組哗咆,它的test設(shè)置為 /node_modules/ 表示只篩選從node_modules文件夾下引入的模塊,所以所有第三方模塊才會被拆分出來益眉。
vendors: {
priority: -10,
test: /node_modules/,
name: "vendor",
enforce: true,
},
}
}
},
})
重新打包,你會發(fā)現(xiàn)沒有效果
output: {
// hash 導(dǎo)致了這里打包freamework依舊重新打包
filename: "js/[name].bundle.[chunkhash:4].js",
path: path.resolve(__dirname, "../dist")
},
再此打包
我們發(fā)現(xiàn)index.bundle.js文件大小只有:1.7kb
我們隨意修改一下app.js中的內(nèi)容再打包一次,你會發(fā)現(xiàn)index.bundle.js(不被緩存)的hash值變了姥份,但是freamework.bundle.js(能被緩存)的hash值沒變
壓縮JS文件
npm install uglifyjs-webpack-plugin --save-dev
將uglifyjs-webpack-plugin引入webpack.prod.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
// optimization內(nèi)配置minimizer參數(shù)
module.exports = merge(common,{
mode:
plugin:[],
optimization:{
minimizer:[new UglifyjsWebpackPlugin()]
splitChunks:{},
}
})
重新打包編譯看看~我們的index.bundle.js減少了5字節(jié)郭脂,當然,隨著業(yè)務(wù)代碼越來越多澈歉,這部分差距會漸漸變大展鸡。
自動編譯打包 webpack-dev-server
npm i webpack-dev-server -D
我們每次修改代碼,查看結(jié)果都要經(jīng)歷以此 npm run build 埃难,大大降低了開發(fā)效率莹弊,這難以忍受!
webpack給我們提供了devServer開發(fā)環(huán)境涡尘,支持熱更新
代碼增加到 webpack.dev.config.js
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
output: {
filename: 'js/[name].[hash:4].bundle.js',
},
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
open: true,
port: 8080,
compress: true,
// 設(shè)置devServer.hot為true忍弛,并且在plugins中引入HotModuleReplacementPlugin插件即可。
// 還需要注意的是我們開啟了hot考抄,那么導(dǎo)出不能使用chunkhash细疚,需要替換為hash。
// 之前我們試過hash會不停的更換名字
hot: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
inject: 'body',
hash: false
}),
//HotModuleReplacementPlugin是webpack熱更新的插件川梅,設(shè)置devServer.hot為true
new webpack.HotModuleReplacementPlugin()
]
});
之后再修改package.json的啟動start
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config ./config/webpack.prod.config.js",
"start": "webpack-dev-server --inline --config ./config/webpack.dev.config.js"
},
好了,我們現(xiàn)在又可以快樂的 npm run start 啟動7杓妗H欢簟!
現(xiàn)在js,html,css,現(xiàn)在前兩架馬車已經(jīng)沒什么問題,我們現(xiàn)在解決css的問題
先讓CSS跑起來
首先我們新建css文件 app.css 并在app中引入
.App{
color: #ff0000;
}
之后我們發(fā)現(xiàn)我們的8080已經(jīng)報錯了,wbpack只能編譯js文件,css文件是無法被識別并編譯的,我們需要loader加載器來進行預(yù)處理吧彪。 首先安裝 style-loader 和 css-loader :
npm i style-loader css-loader -D
遇到后綴為.css的文件待侵,webpack先用css-loader加載器去解析這個文件,遇到“@import”等語句就將相應(yīng)樣式文件引入(所以如果沒有css-loader姨裸,就沒法解析這類語句)秧倾,最后計算完的css,將會使用style-loader生成一個內(nèi)容為最終解析完的css代碼的style標簽啦扬,放到head標簽里中狂。
loader是有順序的,webpack肯定是先將所有css模塊依賴解析完得到計算結(jié)果再創(chuàng)建style標簽扑毡。因此應(yīng)該把style-loader放在css-loader的前面(webpack loader的執(zhí)行順序是從右到左)胃榕。
打包出CSS獨立文件
在我們平時寫css的時候不會將css直接寫在html頁面而是用link標簽引入文件,所以我們也希望通過引入外部css文件進行樣式引入css,我們需要用到mini-css-extract-plugin這個插件
webpack 4.0以后,官方推薦使用extract-text-webpack-plugin插件來打包css文件瞄摊⊙郑可以自己了解
安裝
npm i mini-css-extract-plugin -D
然后將你的webpack.prod.config.js修改
const path = require("path")
const merge = require("webpack-merge");
const common = require("./webpack.common.config");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require("clean-webpack-plugin")
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// ++ 是 minicssexractplugin添加的內(nèi)容
module.exports = merge(common, {
mode: "production",
module:{
rules:[
{
test:/\.css$/,
use:[
++ MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
},
plugins: [
/*
filename:打包之后的html文件名字
template:以我們自己定義的html為模板生成,不然我們還要到打包之后的html文件中寫
inject:在body最底部引入js文件换帜,如果是head楔壤,就是在head中引入js,false不生成js
minify:壓縮html文件,更多配置點我
removeComments:去除注釋
collapseWhitespace:去除空格
*/
new HtmlWebpackPlugin({
filename: "index.html",
template: "public/index.html",
inject: "body",
minify: {
removeComments: true,
collapseWhitespace: true,
}
}),
new CleanWebpackPlugin({
// 項目里有改動才會有新的包 打包編譯前清理dist目錄
cleanOnceBeforeBuildPatterns: [path.resolve(process.cwd(), "dist/*")]
}),
new MiniCssExtractPlugin({
// 這里我們注意一下 在開發(fā)環(huán)境中 我們不加上hash
// 在生產(chǎn)環(huán)境 我們使用hash
++ filename: 'css/[name].[hash].css',
++ chunkFilename: 'css/[id].[hash].css',
})
],
optimization: {
minimizer:[
new UglifyjsWebpackPlugin()
],
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
cacheGroups: {
framework: {
test: "framework",
name: "framework",
enforce: true
},
vendors: {
priority: -10,
test: /node_modules/,
name: "vendor",
enforce: true,
},
}
}
},
})
然后我們 npm run build 打包發(fā)現(xiàn)dist中多了css/index.html,你的css已經(jīng)被打包好了
但是它沒有被壓縮
壓縮打包出的CSS文件
壓縮惯驼,我們需要 optimize-css-assets-webpack-plugin 插件
安裝
npm i optimize-css-assets-webpack-plugin -D
修改webpack.prod.config.js
// 在optimization的minimizer中添加參數(shù)
// OptimizeCssAssetsWebpackPlugin
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = merge(common,{
optimization: {
minimizer:[
new UglifyjsWebpackPlugin(),
new OptimizeCssAssetsWebpackPlugin({
// 正則表達式蹲嚣,用于匹配需要優(yōu)化或者壓縮的資源名。默認值是/.css$/g
assetNameRegExp:/\.css$/g,
// 用于壓縮和優(yōu)化CSS 的處理器祟牲,默認是 cssnano.
cssProcessor:require("cssnano"),
// 傳遞給cssProcessor的插件選項隙畜,默認為{}
cssProcessorPluginOptions:{
// 預(yù)設(shè): '默認', 丟棄注釋: 刪除全部注釋
preset:['default', { discardComments: { removeAll:true } }]
},
//表示插件能夠在console中打印信息说贝,默認值是true
canPrint:true,
}),
],
}
})
另外议惰,這段配置也是可以放到 plugins 這個屬性下進行配置的。 配置完成乡恕,執(zhí)行 npm run build 言询,查看dist目錄下打包出的css文件是不是代碼被壓縮了!
Sass and Less
我們寫項目的時候沒幾個人會去寫css吧傲宜?sass或less對于工作效率的提高是肉眼可見的运杭,但是我們webpack也同樣無法理解這種編寫方式,那就需要配置loader做預(yù)處理函卒,將其轉(zhuǎn)換為css县习。
安裝
npm install --save-dev less less-loader node-sass sass-loader
之后我們開始配置 moudule中的rules loader
module: {
rules: [
//...
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.(sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
]
},
好的,我們執(zhí)行 npm run build 就可以看到sass,less已經(jīng)被轉(zhuǎn)換成css了
我們還需要對css進行補全Postcss
postcss 一種對css編譯的工具,類似babel對js的處理,常見的功能如:
- 使用下一代css語法
- 自動補全瀏覽器前綴
- 自動把px代為轉(zhuǎn)換成rem
- css 代碼壓縮等等
postcss 只是一個工具躁愿,本身不會對css一頓操作叛本,它通過插件實現(xiàn)功能,autoprefixer 就是其一彤钟。
安裝
npm i postcss postcss-loader -D
安裝其中的某個插件比如 Autoprefixer
npm i autoprefixer -D
module.exports = merge(common, {
//...
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
},
]
},
//...
});
接下來我 執(zhí)行 npm run build 打包,
這里有兩個警告(不影響程序的)
- .babelrc 中需要croejs你需要指定 croejs的版本 https://blog.csdn.net/qq_41893551/article/details/90109391
- PostCSS中http://www.reibang.com/p/15d51e796dca
autoprefixer版本高了,引用要修改,需要用新的方法
解決這些之后,就可以快樂的 npm run build
之后我們來配置 webpack.dev.config.js
const merge = require('webpack-merge');
const common = require('./webpack.common.config')
const path = require('path')
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge( common, {
mode:"development",
output:{
filename:"js/[name].[hash:4].bundle.js",
},
devServer: {
//ajax請求的路徑来候,一般可以做mock數(shù)據(jù)用
contentBase: path.resolve(__dirname, '../public'),
// 熱更新
open: true,
// 端口
port: 8080,
historyApifFallback:true,
// 單頁面應(yīng)用切換路由不丟失
compress: true,
hot: true
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader"
]
},
{
test:/\.less$/,
use:[
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader"
]
},
{
test:/\.(sass|scss)/,
use:[
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
}
]
},
plugins:[
//hash選項的作用是 給生成的 jshash 值,該 hash 值是該次 webpack 編譯的 hash 值逸雹。默認值為 false
new HtmlWebpackPlugin({
template:"public/index.html",
inject: 'body',
// hash: false
}),
new MiniCssExtractPlugin({
// 這里我們注意一下 在開發(fā)環(huán)境中 我們不加上hash
// 在生產(chǎn)環(huán)境 我們使用hash
filename: 'css/[name].css',
chunkFilename: 'css/[id].css',
}),
new webpack.HotModuleReplacementPlugin()
]
})
開發(fā)環(huán)境打包壓縮之類的就不需要了,那么css引入還是有兩鐘方式:
- 繼續(xù)以文件方式MiniCssExtractPlugin中將hash去掉
- 以style引入那么就不要用MiniCssExtractPlugin引入css,改用style-loader引入css
到這里我們已經(jīng)實現(xiàn)了一個簡單的react腳手架,不過我還需要進一步優(yōu)化
添加圖片的loader
file-loader 可以對圖片文件進行打包营搅,但是 url-loader 可以實現(xiàn) file-loader 的所有功能,且能在圖片大小限制范圍內(nèi)打包成base64圖片插入到j(luò)s文件中梆砸,這樣做的好處是什么呢转质?先一步一步走著!
安裝url-loader
這里需要注意帖世,url-loader依賴于file-loader休蟹,所有我們兩個loder都要安裝
npm i file-loader url-loader -D //npm install file-loader url-loader --save-dev
在app.js引入圖片
import React from 'react';
import './app.scss';
import background from './asset/img/background.png';
function App() {
return (
<div className="app">
<h1 className="text">Hello Webpack</h1>
<img className="background" src={background} alt=""/>
</div>
);
}
export default App;
并且使用一張css引入
.App {
height: 400px;
display: flex;
justify-content: center;
align-items: center;
div{
width: 100%;
height: 200px;
background:url('./assets/img/background.jpg');
}
img{
height: 200px;
}
h1 {
font-size: 16px;
color: #fff;
}
}
執(zhí)行 npm run build ,你會發(fā)現(xiàn)css的圖片沒有,
在打開index.js之后你會發(fā)現(xiàn)你的圖片路徑是images/background.jpg,很明顯你的圖片路徑不正確,因為你的css和index.html是不同級的index.html在dist的下面,而css在dist/css下載
在webpack.prod.config.js中有處理圖片的loader你可以修改options
options: {
// options中的[name].[ext]表示,輸出的文件名為 原來的文件名.后綴 日矫;
name: '[name].[ext]',
// outputPath是輸出到dist目錄下的路徑赂弓,即dist/images/... ;
outputPath: 'images/',
// limit表示哪轿,如果你這個圖片文件大于8192b盈魁,即8kb,轉(zhuǎn)而去使用file-loader窃诉,
// 減少了http請求杨耙,但是如果文件過大,js文件也會過大飘痛,得不償失珊膜,這是為什么有l(wèi)imit的原因!
limit: 8192,
// publicPath設(shè)置圖片片引入路徑
+ publicPath: '../images/'
},
修改完之后 npm run build
聰明的同學(xué)你一定會反應(yīng)過來index.html的圖片路徑是不對的
可以修改webpack.prod.config.js中sass css less 將其MiniCssExtractPlugin改成options配置參數(shù)
{
test: /\.(sass|scss)/,
use: [
{
loader:MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
"css-loader",
"postcss-loader",
"sass-loader"
]
},
同理 webpack.dev.config.js 也需要這樣配置,
但是如果我們 在development中使用的是 style-loader那么我們的不需要配置,以在style標簽里,路徑和index.html中是一樣的
解決博客https://blog.csdn.net/a806488840/article/details/80920291?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
添加字體圖標loader
字體圖標需要我們之前已經(jīng)安裝過的 file-loader
可以在package.json中j檢查確定有沒有安裝
圖標就不細說了,因為大部分要求項目不一樣
在webpack.common.config.js里配置
module: {
rules: [
//...
{
test: /\.(eot|ttf|svg|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'font/'
}
}
}
]
}
最后我們還需要一個報錯的配置 source-map
這個不需要我們下載,直接在webpack.common.config.js配置
module.exports = {
devtool:"cheap-module-eval-source-map",
entry...
// 現(xiàn)在的webpack高級版本應(yīng)該不需要這個配置瀏覽器也會報錯
// 那我為什么還要寫呢敦冬?畢竟還有用較低版本的同學(xué)。唯沮。脖旱。
}
這些基本的配置完畢之后我還可以配置一些其他東西
process.env
這里的process.env就是Nodejs提供的一個API,
可以直接在webpack.conmmon.config.js中 輸出這個對象
const path = require('path')
console.log( process,'process-------')
module.exports = {
devtool:"cheap-module-eval-source-map",
entry...
// 由于這個對象包含的東西太多就不展示了,我們可以看到里面有一個env
在這個env中我們可以這樣配置
let TARGET = process.env.npm_lifecycle_event; // 是build,還是start
let isDev = process.env.NODE_ENV // 判斷是production 還是 development
console.log(TARGET,isDev)
不過在這之前我們還在要package.json中配置,可以理解為傳遞參數(shù)
在不同的系統(tǒng)比如window環(huán)境變量的命令也有 不同 可以用 cross-env 統(tǒng)一
npm i --save-dev cross-env
{
...
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}
這樣我們可以通過 isDev 這個變量去控制我們的參數(shù)
module.exports = {
mode: isDev === 'production' ? 'production' : 'development'
}
還可以配置resolve
resolve: {
extensions: ['.js', '.jsx', '.json', '.less', '.scss'],
modules: [ path.resolve(__dirname, 'src'), 'node_modules' ],
alias: {
_components: path.join(__dirname, '../src/components'),
_images: path.join(__dirname, '../src/images'),
_pages: path.join(__dirname, '../src/pages'),
_font: path.join(__dirname, '../src/font'),
_util: path.join(__dirname, '../src/util'),
_mock: path.join(__dirname, '../src/mock'),
}
},
// 我們平時引入文件時 通過 import from 引入一個文件 例:import Home from "../src/pages/Home"
// alias的作用就是 import Home from "_pages/Home" 這樣就可以方便快捷的找到Home 并且通過 path 所以我們不用擔 // 心文件路徑不對的問題介蛉,因為我們使用的是絕對路徑
// modules 去哪里尋找第三方模塊 默認就是node_modules 簡單來說你有許多模塊都是在 components文件 中導(dǎo)入
// 原本你可能需要這樣一個很長的路徑 import '../../../components/button
// 設(shè)置好 modules 之后 你只需要import 'button'
https://www.cnblogs.com/joyco773/p/9049760.html
現(xiàn)在我們的基本配置就這些了 !!!
當然只有這些我們的項目還不夠豐滿,
后續(xù)我將會介紹如何在我們自己的"腳手架"中添加更多的模塊
比如 antd UI 或者是 Mobx 再或者我們將使用ts來完成我們的項目