在終端執行npm init
命令生成package.jsoncss
該命令會詢問項目名稱、描述、做者、入口、測試命令等等信息(能夠無論, 直接一路回車)html
本地安裝 eslintnode
npm install eslint --save-dev
複製代碼
eslint官方提供了3種預安裝包, 使用eslint-config-standardreact
npm install eslint-config-standard eslint-plugin-standard eslint-plugin-promise -D
複製代碼
初始化eslint文件webpack
eslint --init
複製代碼
執行eslint --init命令後, 會提示一系列問題如圖,而後在根目錄下生成一文件.eslintrc.js, 修改extends爲standardios
// .eslintrc.js
module.exports = {
"env": {
"browser": true,
"commonjs": true
},
"extends": "standard"
};
複製代碼
由於webpack4.x版本以後 webpack模塊一部分功能分到webpack.cli模塊, 因此二者都須要安裝,具體命令以下web
npm install webpack webpack-cli --global
複製代碼
npm install webpack webpack-cli --save-dev
複製代碼
上述命令可採用簡寫,install可簡寫爲i,--global可簡寫爲-g,--save-dev可簡寫爲-D(這個命令是用於把配置添加到package.json的開發環境配置列表中,後面會提到),--save可簡寫爲-S正則表達式
npm i webpack -g //這是安裝全局webpack命令
npm i webpack webpack-cli -D //這是安裝本地項目模塊
複製代碼
hello.js中 導出一個模塊npm
// hello.js
module.exports = function() {
let hello = document.createElement('div');
hello.innerHTML = "Hello World!";
return hello;
};
複製代碼
index.js中引入該模塊json
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
複製代碼
咱們打包時就只需把index.js模塊打包成bundle.js,而後供index.html引用便可,這就是最簡單的webpack打包原理
webpack全局安裝的狀況下npm install webpack webpack-cli -g
在終端執行如下打包命令
webpack src/index.js --output dist/bundle.js
複製代碼
output能夠簡寫o
新建webpack.config.js, 簡單的配置入口, 出口配置
注:webpack.config.js文件中的__dirname是node.js中的一個全局變量,它指向當前執行腳本所在的目錄 即D:\GitLab\webpack4
注:path.join的功能是拼接路徑片斷。
有了這個配置文件,咱們只需在終端中運行webpack命令就可進行打包,這條命令會自動引用webpack.config.js文件中的配置選項,示例以下:
![]()
{
"name": "webpack4",
"version": "1.0.0",
"description": "webpack4嚐鮮",
"main": "index.js",
"scripts": {
"start": "webpack",
"test": "npm run test"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.23.1",
"webpack-cli": "^3.1.2"
}
}
複製代碼
咱們就能夠在終端中直接執行npm start命令來進行打包,start命令比較特殊,能夠直接npm加上start就能夠執行,若是咱們想起其餘的名稱,如build時,就須要使用npm run加上build,即npm run build
命令。 如今咱們執行npm start命令
Webpack提供了一個可選的本地開發服務器,這個本地服務器基於node.js構建,它是一個單獨的組件,在webpack中進行配置以前須要單獨安裝它做爲項目依賴
安裝命令:
npm i webpack-dev-server -D
- contentBase :設置服務器所讀取文件的目錄,當前咱們設置爲"./dist"
- port :設置端口號,若是省略,默認爲8080
- inline :設置爲true,當源文件改變時會自動刷新頁面
- historyApiFallback :設置爲true,全部的跳轉將指向index.html
// webpack.config.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
// 本地服務器配置
devServer: {
contentBase: './dist', // 本地服務器所加載文件的入口
port: '8080', // 端口號8080
inline: true, // 修改源碼文件後實時刷新
historyApiFallback: true // 不跳轉
}
}
複製代碼
在package.json 文件配置啓動服務器命令webpack-dev-server --open
// package.json
{
...
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open",
"test": "npm run test"
},
...
}
複製代碼
咱們把start命令名稱改成了build,這樣比較語義化,平時的腳手架也多數採用這個名稱,咱們用dev(development的縮寫,意指開發環境)來啓動本地服務器,webpack-dev-server就是啓動服務器的命令,--open是用於啓動完服務器後自動打開瀏覽器,這時候咱們自定義命令方式的便捷性就體現出來了,能夠多個命令集成在一塊兒運行,即咱們定義了一個dev命令名稱就能夠同時運行了webpack-dev-server和--open兩個命令
做爲開發,代碼調試固然少不了,那麼問題來了,通過打包後的文件,你是不容易找到出錯的地方的,Source Map就是用來解決這個問題的 經過以下配置,咱們會在打包時生成對應於打包文件的.map文件,使得編譯後的代碼可讀性更高,更易於調試。
// webpack.config.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
// 本地服務器配置
devServer: {
contentBase: './', // 本地服務器所加載文件的入口
port: '8080', // 設置端口號,若是省略,默認爲8080
inline: true, // 設置爲true,當源文件改變時會自動刷新頁面
historyApiFallback: false // 設置爲true,全部的跳轉將指向index.html
},
devtool: 'source-map' // 會生成對於調試的完整的.map文件,但同時也會減慢打包速度
}
複製代碼
配置好後,咱們再次運行npm run build進行打包,這時咱們會發如今dist文件夾中多出了一個bundle.js.map文件 若是咱們的代碼有bug,在瀏覽器的調試工具中會提示錯誤出現的位置,這就是devtool: 'source-map'配置項的做用。
loaders是webpack最強大的功能之一,經過不一樣的loader,webpack有能力調用外部的腳本或工具,實現對不一樣格式的文件的處理,例如把scss轉爲css,將ES6六、ES7等語法轉化爲當前瀏覽器能識別的語法,將JSX轉化爲js等多項功能。
Loaders須要單獨安裝而且須要在webpack.config.js中的modules配置項下進行配置,Loaders的配置包括如下幾方面:
- test:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)
- loader:loader的名稱(必須)
- include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);
- options:爲loaders提供額外的設置選項(可選)
若是咱們要加載一個css文件,須要安裝配置style-loader和css-loader:
安裝css-loader與其依賴:
npm i style-loader css-loader -D
配置文件如今爲
// webpack.config.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
// 本地服務器配置
devServer: {
contentBase: './', // 本地服務器所加載文件的入口
port: '8080', // 設置端口號,若是省略,默認爲8080
inline: true, // 設置爲true,當源文件改變時會自動刷新頁面
historyApiFallback: false // 設置爲true,全部的跳轉將指向index.html
},
devtool: 'source-map', // 會生成對於調試的完整的.map文件,但同時也會減慢打包速度
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: ['style-loader', 'css-loader'] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
}
]
}
}
複製代碼
在src文件夾下新建css文件夾,在css文件夾下新建index.css文件 而且在index.js中引入
import './css/index.css'
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
複製代碼
安裝:
npm i sass-loader node-sass -D // 由於sass-loader依賴於node-sass,因此還要安裝node-sass
複製代碼
配置SASS的rules
// webpack.config.js
const path = require('path')
module.exports = {
...
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: ['style-loader', 'css-loader'] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
},
{
test: /\.(scss|sass)$/, // 正則匹配以.scss和.sass結尾的文件
use: ['style-loader', 'css-loader', 'sass-loader'] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
}
]
}
}
複製代碼
css文件夾下新建red.scss文件
$--red-color: red;
body{
color: $--red-color;
}
複製代碼
index.js中引入red.scss
import './css/red.scss'
import './css/index.css'
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
複製代碼
Babel 是一個 JavaScript 編譯器 Babel 是一個工具鏈,主要用於在舊的瀏覽器或環境中將 ECMAScript 2015+ 代碼轉換爲向後兼容版本(ES六、ES七、ES8...)的 JavaScript 代碼。如下是Babel 能夠爲你作的主要事情
- (1)、轉換語法
- (2)、Polyfill 實現目標環境中缺乏的功能 (經過 @babel/polyfill)
- (3)、源代碼轉換 (codemods)
- (4)、基於JavaScript進行拓展的語言, 例如JSX
Babel實際上是幾個模塊化的包,其核心功能位於稱爲babel-core的npm包中,webpack能夠把其不一樣的包整合在一塊兒使用,對於每個你須要的功能或拓展,你都須要安裝單獨的包(用得最多的是解析ES6的babel-preset-env包和解析JSX的babel-preset-react包)。
npm install -D babel-loader @babel/core @babel/preset-env // babel-preset-env的env表示是對當前環境的預處理,而不是像之前使用babel-preset-es2015只能針對某個環境
複製代碼
const path = require('path')
module.exports = {
...
module: {
rules: [
...
{
test: /\.(js|jsx)$/,
use: { // 注意use選擇若是有多項配置,可寫成這種對象形式
loader: 'babel-loader'
// options: { // 後續Babel配置會單獨提取到.babelrc文件中
// presets: [ '@babel/preset-env' ] // 支持最新JS語法(ES六、ES七、ES8。。。)
// }
},
exclude: /node_modules/ // 排除匹配node_modules模塊
}
]
}
}
複製代碼
插件(Plugins)是用來拓展Webpack功能的,它們會在整個構建過程當中生效,執行相關的任務。
Loaders和Plugins經常被弄混,可是他們實際上是徹底不一樣的東西,能夠這麼來講,loaders是在打包構建過程當中用來處理源文件的(JSX,Scss,Less..),一次處理一個,插件並不直接操做單個文件,它直接對整個構建過程其做用。
使用某個插件,須要經過npm進行安裝,而後在webpack.config.js配置文件的plugins(是一個數組)配置項中添加該插件的實例,下面咱們先來使用一個簡單的版權聲明插件.
// webpack.config.js
...
module.exports = {
...
plugins: [
new webpack.BannerPlugins('版權全部,翻版必究') // new一個插件的實例
]
}
複製代碼
新建.babelrc文件, 將Babel配置收取至.babelrc文件中
{
"presets": [ "@babel/preset-env" ]
}
複製代碼
咱們都是使用的模板index.html, 那麼怎麼自動引入打包生成以後的JS文件?HtmlWebpackPlugin插件就是用來解決這個問題的
安裝該插件npm i html-webpack-plugin -D
在src文件夾下新建index.html的文件模板(固然這個是可選的,由於就算不設置模板,HtmlWebpackPlugin插件也會生成默認html文件,這裏咱們設置模塊會讓咱們的開發更加靈活),以下:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製代碼
webpack.config.js中咱們引入了HtmlWebpackPlugin插件,並配置了引用了咱們設置的模板,以下:
// webpack.config.js
const path = require('path') // 路徑處理模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
....
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html') // new一個這個插件的實例,並傳入相關的參數
})
]
}
複製代碼
你可能已經注意到,在咱們刪掉/dist文件夾以前,因爲前面的代碼示例遺留,致使咱們的/dist文件夾比較雜亂。webpack會生成文件,而後將這些文件放置在/dist文件夾中,可是webpack沒法追蹤到哪些文件是實際在項目中用到的。
一般,在每次構建前清理/dist文件夾,是比較推薦的作法,所以只會生成用到的文件,這時候就用到CleanWebpackPlugin插件了。 安裝:
npm i clean-webpack-plugin -D
// webpack.config.js
const path = require('path') // 路徑處理模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一個這個插件的實例,並傳入相關的參數
}),
new ClearWebpackPlugin(['dist']) // 清理所要清理的文件夾名稱
]
}
複製代碼
插件的使用方法都是同樣的,首先引入,而後new一個實例,實例可傳入參數。 如今咱們運行npm run build後就會發現,webpack會先將/dist文件夾刪除,而後再生產新的/dist文件夾。
HotModuleReplacementPlugin(HMR)是一個很實用的插件,能夠在咱們修改代碼後自動刷新預覽效果。
方法:
- (1):devServer配置項中添加hot: true參數。
- (2):由於HotModuleReplacementPlugin是webpack模塊自帶的,因此引入webpack後,在plugins配置項中直接使用便可。
// webpack.config.js
const path = require('path') // 路徑處理模塊
const webpack = require('webpack') // 這個插件不須要安裝,是基於webpack的,須要引入webpack模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
...
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一個這個插件的實例,並傳入相關的參數
}),
new ClearWebpackPlugin(['dist']), // 清理所要清理的文件夾名稱
new webpack.HotModuleReplacementPlugin() // 熱更新插件
]
}
複製代碼
此時咱們從新啓動項目npm run dev後,修改hello.js的內容,會發現瀏覽器預覽效果會自動刷新(也許反應會比較慢,由於咱們使用了source-map和其餘配置的影響,後面代碼分離的時候咱們再處理)。
在當前的開發環境都是提倡模塊化,webpack天然不例外,咱們前面的webpack.config.js配置文件,其實也沒配置多少東西就這麼多了,要是之後增長了更多配置,豈不是看得眼花繚亂,因此最好的方法就是把它拆分,方便管理:
- 根目錄下新建webpack.common.js(公共配置文件)、webpack.dev.js(開發環境配置文件)、webpack.prod.js(生產環境配置文件)
安裝一個合併模塊插件webpack-merge
npm i webpack-merge -D
複製代碼
- 拆分webpack.config.js。 刪除webpack.config.js。具體實現以下
// webpack.common.js
const path = require('path') // 路徑處理模塊
const webpack = require('webpack') // 這個插件不須要安裝,是基於webpack的,須要引入webpack模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: ['style-loader', 'css-loader'] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
},
{
test: /\.(scss|sass)$/, // 正則匹配以.scss和.sass結尾的文件
use: ['style-loader', 'css-loader', 'sass-loader'] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
},
{
test: /\.(js|jsx)$/,
use: { // 注意use選擇若是有多項配置,可寫成這種對象形式
loader: 'babel-loader'
// options: { // 後續Babel配置會單獨提取到.babelrc文件中
// presets: [ 'env' ] // 支持最新JS語法(ES六、ES七、ES8。。。)
// }
},
exclude: /node_modules/ // 排除匹配node_modules模塊
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一個這個插件的實例,並傳入相關的參數
}),
new webpack.HotModuleReplacementPlugin() // 熱更新插件
]
}
複製代碼
// webpack.prod.js
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
const merge = require('webpack-merge')
const common = require('./webpack.common')
module.exports = merge(common, {
devtool: 'source-map', // 會生成對於調試的完整的.map文件,但同時也會減慢打包速度
plugins: [
new ClearWebpackPlugin(['dist']) // 清理所要清理的文件夾名稱
]
})
複製代碼
// webpack.dev.js
const merge = require('webpack-merge')
const common = require('./webpack.common')
module.exports = merge(common, {
// 本地服務器配置
devServer: {
contentBase: './', // 本地服務器所加載文件的入口
port: '8080', // 設置端口號,若是省略,默認爲8080
inline: true, // 設置爲true,當源文件改變時會自動刷新頁面
historyApiFallback: false, // 設置爲true,全部的跳轉將指向index.html
hot: true // 熱加載
}
})
複製代碼
- 設置package.json的scripts命令:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server --open --config src/webpack.dev.js",
"test": "npm run test"
},
...
}
複製代碼
咱們把build命令改成了webpack --config webpack.prod.js,意思是把打包配置指向webpack.prod.js配置文件,而以前咱們只須要使用一個webpack命令爲何就能夠運行了?由於webpack命令是默認指向webpack.config.js這個文件名稱了,如今咱們把文件名稱改了,因此就須要自定義指向新的文件,dev命令中的指令也同理。 而後咱們運行npm run build和npm run dev,效果應該和咱們分離代碼前是同樣的。
注:說道package.json文件,順便就多提幾句,由於也許有些朋友可能對咱們安裝模塊時加的-D、-S或-g命令存在一些疑惑,由於不知道何時加什麼尾綴。 其實這個package.json文件是用於咱們安裝依賴的,能夠把它當成一份依賴安裝說明表,就是若是咱們把項目上傳或者發給其餘的開發同事,確定不會把/node_modules文件夾也發送過去,由於這太大了,不現實也不必。 開發同事只須要有這份package.json文件,而後npm install就能夠把咱們所須要的依賴都安裝下來,但前提是package.json文件上有記錄,這就是安裝模塊時加上-D,-S命令的緣由。 -D的全稱是--save-dev指開發環境時須要用到的依賴,會記錄在package.json文件中的devDependencies選項中,而-S是--save是指生產環境也就是上線環境中須要用到的依賴,會記錄在package.json文件中的dependencies選項中,-g的全稱是--global指安裝全局命令,就是咱們在本電腦的任何項目中都能使用到的命令,好比安裝cnpm這個淘寶鏡像命令就會用到-g命令。 因此咱們在安裝模塊時必定不要忘了加上對應的尾綴命令,讓咱們的模塊有跡可循,不然其餘的開發同事接手你的項目的話,會不會下班後(放學後)在門口等你就不知道了。
平時咱們寫css時,一些屬性須要手動加上前綴,好比-webkit-border-radius: 10px;,在webpack中咱們能不能讓它自動加上呢?那是必須的,首先確定得安裝模塊了:
npm i postcss-loader autoprefixer -D
複製代碼
安裝好這兩個模塊後,在項目根目錄下新建postcss.config.js文件:
module.exports = {
plugins: [
require('autoprefixer') // 引用autoprefixer模塊
]
}
複製代碼
index.css中增長如下樣式
body {
background: gray;
}
#root div{
width: 200px;
margin-top: 50px;
transform: rotate(45deg); /* 這個屬性會產生前綴 */
}
複製代碼
修改webpack.common.js文件中的css-loader配置:
// webpack.common.js
const path = require('path') // 路徑處理模塊
const webpack = require('webpack') // 這個插件不須要安裝,是基於webpack的,須要引入webpack模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: [
{ loader: 'style-loader' }, // 這裏採用的是對象配置loader的寫法
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
},
...
]
}
}
複製代碼
而後咱們運行npm run dev後css樣式中會自動添加前綴
雖然webpack的理念是把css、js全都打包到一個文件裏,但要是咱們想把css分離出來該怎麼作呢?
npm i extract-text-webpack-plugin@next -D // 加上@next是爲了安裝最新的,不然會出錯
複製代碼
安裝完以上插件後在webpack.common.js文件中引入並使用該插件:
// webpack.common.js
const path = require('path') // 路徑處理模塊
const webpack = require('webpack') // 這個插件不須要安裝,是基於webpack的,須要引入webpack模塊
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ExtractTextPlugin = require('extract-text-webpack-plugin') // 引入分離插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包後的文件存放的地方
filename: 'bundle.js' // 打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
] // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
})
},
...
]
},
plugins: [
...
new ExtractTextPlugin('css/index.css') // 將css分離到/dist文件夾下的css文件夾中的index.css
]
}
複製代碼
有時候咱們css寫得多了,可能會不自覺的寫重複了一些樣式,這就形成了多餘的代碼,上線前又忘了檢查,對於這方面,咱們應該儘可能去優化它,webpack就有這個功能。
npm i purifycss-webpack purify-css glob -D
複製代碼
安裝完上述三個模塊後,由於正常來講是在生產環境中優化代碼,因此咱們應該是在webpack.prod.js文件中進行配置,引入clean-webpack-plugin及glob插件並使用它們:
// webpack.prod.js
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
const merge = require('webpack-merge')
const common = require('./webpack.common')
const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模塊,用於掃描所有html文件中所引用的css
module.exports = merge(common, { // 將webpack.common.js合併到當前文件
devtool: 'source-map', // 會生成對於調試的完整的.map文件,但同時也會減慢打包速度
plugins: [
new ClearWebpackPlugin(['dist']), // 清理所要清理的文件夾名稱
new PurifyCssWebpack({
paths: glob.sync(path.join(__dirname, 'src/*.html')) // 同步掃描全部html文件中所引用的css
})
]
})
複製代碼
在index.css文件中增長一些多餘的代碼測試:
body {
background: gray;
}
#root div{
width: 200px;
margin-top: 50px;
transform: rotate(45deg); /* 這個屬性會產生前綴 */
}
.a{ /* 冗餘css */
color: black;
}
.b{ /* 冗餘css */
width: 50px;
height: 50px;
background: yellow;
}
複製代碼
而後咱們運行npm run build後發現打包後的index.css中是沒有多餘的.a和.b代碼的:
body {
background: gray;
}
#root div {
width: 200px;
margin-top: 50px;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
/* 這個屬性會產生前綴 */
}
/*# sourceMappingURL=index.css.map*/
複製代碼
處理圖片須要安裝兩個loader:
雖然咱們只需使用url-loader,但url-loader是依賴於file-loader的,因此也要安裝
npm i url-loader file-loader -D
複製代碼
而後在webpack.common.js中配置url-loader:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正則匹配圖片格式
use: [
{
loader: 'url-loader' // 使用url-loader
}
]
}
]
},
...
}
複製代碼
更新index.css, 背景改成背景
body {
background: gray;
background-image: url(../images/back.png) top right repeat-y;
}
...
複製代碼
運行npm run dev後,背景圖片變成了base64,由於webpack會自動優化圖片,減小發送請求,可是若是我想把它變成路徑的該怎麼作? 能夠把webpack.common.js的loader配置更改一下,增長options選項:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正則匹配圖片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000 // 限制只有小於1kb的圖片才轉爲base64,例子圖片爲384kb,因此不會被轉化
}
}
]
}
]
},
...
}
複製代碼
而後咱們運行npm run build後,再運行npm run dev,額,圖片是沒有轉成base64了,可是圖片怎麼不顯示了? 問題就出在路徑上,咱們以前圖片的路徑是在../images文件夾下,可是打包出來後沒有這個路徑了,圖片直接和文件同級了,因此咱們須要在webpack.common.js中給它設置一個文件夾:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正則匹配圖片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000, // 限制只有小於1kb的圖片才轉爲base64,例子圖片爲384kb,因此不會被轉化
outputPath: 'images' // 設置打包後圖片存放的文件夾名稱
}
}
]
}
]
},
...
}
複製代碼
繼續npm run build打包再npm run dev運行,個人天!圖片仍是不顯示! 調試工具上看圖片路徑有images文件夾了,可是個人../呢?
這涉及到配置路徑的問題上了,咱們還須要在css-loader中給背景圖片設置一個公共路徑publicPath: '../',以下:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.css$/, // 正則匹配以.css結尾的文件
use: ExtractTextPlugin.extract({ // 這裏咱們須要調用分離插件內的extract方法
fallback: 'style-loader', // 至關於回滾,經postcss-loader和css-loader處理過的css最終再通過style-loader處理
use: [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
], // 須要用的loader,必定是這個順序,由於調用loader是從右往左編譯的
publicPath: '../' // 給背景圖片設置一個功能路徑
})
},
{
test: /\.(png|jpg|svg|gif)$/, // 正則匹配圖片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000, // 限制只有小於1kb的圖片才轉爲base64,例子圖片爲384kb,因此不會被轉化
outputPath: 'images' // 設置打包後圖片存放的文件夾名稱
}
}
]
}
]
},
...
}
複製代碼
在webpack4.x版本中當你打包時會自動把js壓縮了,並且npm run dev運行服務器時,當你修改代碼時,熱更新很慢,這是由於你修改後webpack又自動爲你打包,這就致使了在開發環境中效率很慢,因此咱們須要把開發環境和生產環境區分開來,這時就體現出咱們代碼分離的便捷性了,webpack.dev.js表明開發環境的配置,webpack.prod.js表明生產環境的配置,這時咱們只要在package.json文件中配置對應環境的命令便可:
{
...
"scripts": {
"build": "webpack --config webpack.prod.js --mode production",
"dev": "webpack-dev-server --open --config webpack.dev.js --mode development",
"test": "npm run test"
},
...
}
複製代碼
--mode production表示打包時是生產環境,會本身將js進行壓縮,而--mode development表示當前是開發環境,不須要進行壓縮。這同時也解決了以前一直遺留的警告問題
項目背景:項目有三個分支、dev(開發分支)、uat(測試環境)、prod(上線環境) 如今須要:運行對應的命令npm run dev:dev、uat、prod以及npm run build:dev、uat、prod會調用對用的host
步驟以下
- 一、cross-env能跨平臺地設置及使用環境變量,安裝
npm i --save-dev cross-dev
- 二、config文件夾下新建dev.js(開發環境)、prod.js(生產環境)。配置文件以下
// dev.js
// 在任何文件裏都能簡單的用下面代碼獲取到配置
// const NODE_ENV = process.env.NODE_ENV
// const BRANCH = process.env.BRANCH
module.exports = {
NODE_ENV: "'development'", // 開發模式|生產模式
/*
* 一、process.env.BRANC 讀取終端執行的npm命令
* 二、BRANCH: JSON.stringify(process.env.BRANCH) || 'dev':用於接受npm命令的修改
* 三、默認dev
*/
BRANCH: JSON.stringify(process.env.BRANCH) || "'dev'"
}
複製代碼
// prod.js
// 在任何文件裏都能簡單的用下面代碼獲取到配置
// const NODE_ENV = process.env.NODE_ENV
// const BRANCH = process.env.BRANCH
module.exports = {
NODE_ENV: "'production'", // 開發模式|生產模式
/*
* 一、process.env.BRANC 讀取終端執行的npm命令
* 二、BRANCH: JSON.stringify(process.env.BRANCH) || 'dev':用於接受npm命令的修改
* 三、默認dev
*/
BRANCH: JSON.stringify(process.env.BRANCH) || "'dev'"
}
複製代碼
- 三、在package.json中配置npm 腳本以下:
{
...
"scripts": {
"dev": "webpack-dev-server --open --config webpack.dev.js --mode development",
"dev:dev": "cross-env BRANCH=dev webpack-dev-server --open --config webpack.dev.js --mode development"
...
},
...
}
複製代碼
- 四、在webpack.dev.js中引入dev.js,webpack.prod.js引入prod.js 並將其設置爲全局變量,具體以下
// webpack.dev.js
const dev = require('./config/dev')
...
module.exports = merge(common, {
...
plugins: [
new webpack.DefinePlugin({ // DefinePlugin能夠在編譯時期建立全局變量。
'process.env': dev
})
]
})
複製代碼
// webpack.prod.js
...
const dev = require('./config/prod')
module.exports = merge(common, { // 將webpack.common.js合併到當前文件
plugins: [
...
new webpack.DefinePlugin({ // DefinePlugin能夠在編譯時期建立全局變量。
'process.env': dev
})
]
})
複製代碼
- 五、 config文件下新建common.js,用於存放公共的方法,並配置
// common.js
module.exports = {
/**
* [getHost 根據執行腳本的具體命令,返回具體的請求IP]
* @return {[type]} [description]
*/
getHost () {
const BRANCH = `${process.env.BRANCH}`
let HOST = ''
switch (BRANCH) {
case 'dev' :
HOST = 'https://xxx.com'
break
default :
HOST = ''
}
return HOST
}
}
複製代碼
- 六、 分別運行npm run build npm run dev使用. 就能夠看到效果
// index.js
const { post } = require('./preset/request')
const promise = post({
url: '/xxx/xxx',
data: {
tenantCode: '88000531',
keyword: '',
page: {
size: 10,
page: 1
}
}
})
promise.then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
複製代碼
運行npm run build:dev,這樣NODE_ENV便設置成功,無需擔憂跨平臺問題 在任何頁面使用都能獲取process.env.BRANCH
Axios具備如下特徵:
- 從瀏覽器中建立 XMLHttpRequests
- 從 node.js 建立 http 請求
- 支持 Promise API 攔截請求和響應 轉換請求數據和響應數據 取消請求 自動轉換 JSON 數據 客戶端支持防護 XSRF
安裝命令:npm install axios
封裝請求的request.js
const HOST = require('../../config/common').getHost() // 獲取命令後綴
const _axios = require('axios') // 使用axios
const axios = _axios.create({ // 建立實例
baseURL: HOST, // IP
timeout: 5000 // 請求超時時間
})
// 配置默認值
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
/**
* [description]
* @param {[type]} url [請求地址]
* @param {[type]} params [請求參數, 與url拼接的]
* @param {[type]} headers [請求頭]
* @param {[type]} timeout [超時時間]
* @return {[type]} [返回promise]
*/
module.exports.get = function ({ url = '', params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.get(url, { params, timeout })
return promise
}
/**
* [POST請求]
* @param {[type]} url [請求地址]
* @param {[type]} data [請求參數]
* @param {[type]} params [地址拼接參數]
* @param {[type]} headers [請求頭]
* @param {[type]} timeout [超時]
* @return {[type]} [返回promise]
*/
module.exports.post = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.post(url, { data, params, headers, timeout })
return promise
}
/**
* [PUT請求]
* @param {[type]} url [請求地址]
* @param {[type]} data [請求參數]
* @param {[type]} params [地址拼接參數]
* @param {[type]} headers [請求頭]
* @param {[type]} timeout [超時]
* @return {[type]} [返回promise]
*/
module.exports.put = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.put(url, { data, params, headers, timeout })
return promise
}
/**
* [DELETE請求]
* @param {[type]} url [請求地址]
* @param {[type]} data [請求參數]
* @param {[type]} params [地址拼接參數]
* @param {[type]} headers [請求頭]
* @param {[type]} timeout [超時]
* @return {[type]} [返回promise]
*/
module.exports._delete = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.delete(url, { data, params, headers, timeout })
return promise
}
複製代碼