使用包的版本css
webpack ->4.3.0
babel-loader ->8.0.5
npm ->6.4.1
webpack-cli ->3.3.1
複製代碼
每一個章節對應一個demohtml
進入項目目錄,運行 npm init來建立項目vue
npm init
複製代碼
終端輸入完成後會自動建立一個package.json的文件。node
{
"name": "demo1",
"version": "1.0.0",
"description": "webpack-demo",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack app.js"
},
"keywords": [
"demo"
],
"author": "cmf",
"license": "ISC",
"devDependencies": {}
}
複製代碼
運行命令,引入webpack和webpack-cli,安裝webpack-cli是爲了在項目裏面運行webpack命令。webpack
npm i webpack webpack-cli -D
複製代碼
手動建立webpack.config.js。css3
touch webpack.config.js
複製代碼
在終端裏面經過npx運行webpack命令沒法進行復雜配置。因此建立webpack.config.js是爲了後面的複雜配置。 新建app.js、index.html、view文件夾、view文件夾裏面建立dom.js。git
mkdir view
touch app.js
cd view
touch app.js
複製代碼
代碼內容詳見demo1 配置 webpack.config.jses6
npx webpack
複製代碼
"scripts": {
"build": "webpack"
},
複製代碼
這兩種方式都會自動尋找項目裏面的webpack包進行打包,而且webpack會根據webpack.config.js的配置規則進行打包。github
npm i cross-env html-webpack-plugin webpack-dev-server -D
複製代碼
cross-env 跨平臺的解決了環境變量和參數的命令配置。
html-webpack-plugin 打包生成HTML的插件。
webpack-dev-server建立開發服務器。功能強大,接口轉發、熱更新等。web
新建index.html、help.js
touch index.html
touch help.js
複製代碼
index.html 模板文件
<head>
<title>demo2</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</head>
<body>
<div id="app"></div>
</body>
複製代碼
help.js 封裝的一些方法。
module.exports.getMode = function() {
return process.env.NODE_ENV === 'development'?'development':'production'
};
複製代碼
webpack-dev-server其餘配置請參考官方文檔。
mode模式。默認值是production。 告知 webpack 使用相應模式的內置優化。是 webpack4新增的屬性。好比mode是production,webpack會默認添加一些打包插件好比:NoEmitOnErrorsPlugin。能夠節省不少配置。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "cross-env NODE_ENV=production webpack",
"dev": "cross-env NODE_ENV=development webpack-dev-server"
},
複製代碼
cross-env NODE_ENV=production 設置環境變量信息
npm run dev
複製代碼
自動打開瀏覽器,會把app.js裏面的內容自動注入到index.html裏面。
代碼內容詳見demo3
externals防止將某些 import 的包是從外部獲取依賴不是從node_modules裏面獲取的。
例如咱們在app.js裏面
// app.js
import Vue from 'Vue';
複製代碼
index.html
<head>
<title>demo4</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
複製代碼
webpack.config.js
externals:{ //外部擴展
'Vue':'window.Vue'
},
複製代碼
如今app.js 裏面引入的Vue是從cdn裏面引入的,而不是從node_modules包裏面引入的。 這樣作的好處:
resolve開發者能夠自定義解析規則。
resolve.modules 自定義依賴包的路徑。參數是array,能夠是相對目錄也能夠是絕對目錄。默認是 [path.resolve(process.cwd(),'node_modules')]。當前命令的目錄下面的node_modules文件夾。
若是一個大的項目裏面有不少子項目,每一個子項目不必都安裝依賴包,因此能夠在各個子項目裏面經過配置resolve.modules指向母項目的node_modules包。
resolve.modules 自定義引入模塊時能夠不帶擴展名。參數是array。默認['.js','.json']
extensions:['.js','.vue','.json','.css','.less'],
複製代碼
代碼裏面
import 'view/dom'
複製代碼
會自動找到dom.js
resolve.alias 自定義路徑別名。參數是object。
alias:{
'@': path.resolve(__dirname, './src')
},
// __dirname 當前文件的目錄地址。
複製代碼
在代碼裏可使用@符號指向src目錄。
import '@/view/dom.js';
複製代碼
好處:在很深的代碼層裏面若是想引入頂層的某個js文件。不須要寫不少'../../../'去找文件,提升開發效率。
resolve裏面有不少的自定義解析規則。有時間均可以嘗試一下。
代碼內容詳見demo4
雖然在webpack4裏面提供了mode屬性來分別打包開發和生產環境,各自提供不一樣的插件。可是若是clean-webpack-plugin插件想在生產環境使用在開發環境不使用,就須要每次手動更改配置,這樣作很不合理,容易出錯。
可使用
webpack --config 配置文件
複製代碼
npm i webpack-merge -D
複製代碼
新建build文件夾
mkdir build
cd build
touch weboack.build.conf.js、webpack.base.conf.js、webpack.dev.conf.js config.js help.js
複製代碼
help.js 儲層公共方法
var path = require('path');
module.exports.getMode = function() {
return process.env.NODE_ENV === 'development'?'development':'production'
};
module.exports.resolve = function(p){
return path.resolve(process.cwd(),p);
}
複製代碼
config.js 開發與生產的配置信息
module.exports = {
dev: {
mode: 'development',
publicPath: '/',
devServer: {
port: '8899',
proxy: {
'/test/shortRent': {
target: 'http:"//www.baidu.com',
changeOrigin: true,
pathRewrite: {
'^/test/shortRent': '/evcard-evrental'
}
},
},
},
},
build: {
mode: 'production',
publicPath: './',
assetsRoot: 'you-app'
}
}
複製代碼
webpack.base.conf.js 開發與生產相同的webpack配置
var path = require('path');
var help = require('./help.js');
var config = require('./config.js');
var htmlWebpackPlugin = require('html-webpack-plugin');
var mode = help.getMode();
module.exports={
entry:{
app:help.resolve('./app.js')
},
output:{
},
resolve:{ // 解析
alias:{
'@': help.resolve('./src')
},
extensions:['.js','.vue','.json','.css','.less'],
modules: ["./node_modules"]
},
externals:{ //外部擴展
'Vue':'window.Vue'
},
plugins:[
new htmlWebpackPlugin({
filename:'index.html',
template:'./index.html',
inject:true,
})
],
}
複製代碼
webpack.dev.conf.js 開發環境的webpack配置
var merge = require("webpack-merge");
var webpackConfigBase = require('./webpack.base.conf');
var help = require('./help.js');
var config = require('./config.js');
module.exports=merge(webpackConfigBase,{
mode: config.dev.mode,
output:{
filename:help.assetsPath('js/[name].js'),
publicPath:config.dev.publicPath
},
devServer:config.dev.devServer
})
複製代碼
webpack.build.conf.js 生產環境的webpack配置
var cleanWebpackPlugin = require('clean-webpack-plugin');
var merge = require("webpack-merge");
var help = require('./help.js');
var webpackConfigBase = require('./webpack.base.conf.js');
var config = require('./config.js');
module.exports=merge(webpackConfigBase,{
mode: config.build.mode,
output:{
filename:'assets/js/[name].[hash].js',
publicPath:config.build.publicPath,
path:help.resolve(config.build.assetsRoot),
},
plugins:[
new cleanWebpackPlugin()
]
})
複製代碼
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/weboack.build.conf.js",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.conf.js"
},
複製代碼
代碼內容詳見demo5
loader 用來解析文件轉譯成瀏覽器能夠識別的文件。如.less、.vue、.jsx等這些文件瀏覽器是不能正常轉譯的,loaders的做用就是充當着'翻譯'的做用。
咱們在開發的時候都使用es6的語法去編寫代碼,可是有些瀏覽器不支持es6的代碼就須要將es6轉譯成瀏覽器能夠讀懂的es5的代碼。babel-loader的做用就是'翻譯'es6代碼。
安裝babel-loader。參照官方的安裝方式,打開官網選擇webpack的安裝方式。
安裝依賴
npm install --save-dev babel-loader @babel/core
npm install @babel/preset-env --save-dev
複製代碼
babel-loader @babel/core 是核心插件
preset-env 編譯方式
配置規則
module: {
rules: [
{
test: /\.js$/, // 正則匹配,全部的.js文件都使用這個規則進行編譯
exclude: /node_modules/, // 排除的文件夾。這個文件夾裏面的的文件不進行轉譯
loader: "babel-loader", // 轉譯的插件
options: { // 轉譯的規則
presets: [ //轉譯器配置
[
"@babel/preset-env"
]
],
plugins: [] // 轉譯插件配置
}
},
]
}
複製代碼
plugins(轉譯插件)。轉譯插件是用來轉譯單一功能的插件,好比transform-es2015-arrow-functions,這個插件只負責轉譯es2015新增的箭頭函數。
presets(轉譯器)。轉譯器是一系列轉譯插件的集合。好比babel-preset-es2015就包含了es2015新增語法的全部轉譯插件,好比包含transform-es2015-arrow-functions(es2015箭頭函數轉譯插件)、transform-es2015-classes(es2015 class類轉譯插件)等。轉譯器分爲語法轉譯器和補丁轉譯器。 詳解
在app.js裏面寫es6的代碼
const s = new Set([1, 2, 3, 4, 5, 3, 2, 16, 7, 83, 21, 2, 1]);
var w = Object.assign({}, { w: 1, e: 4 })
console.log(w);
console.log([...s]);
function pro(v) {
return new Promise((resolve) => {
if (v) {
resolve('真11')
} else {
resolve('假22')
}
})
}
pro(true).then(res=>{
console.log(res)
})
複製代碼
運行命令
npm run build
複製代碼
npm run dev
複製代碼
Babel 默認只轉換新的 JavaScript 句法(syntax),而不轉換新的 API,好比 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局對象,以及一些定義在全局對象上的方法(好比 Object.assign)都不會轉碼。
因此還須要配置。 在babel@7.4之前使用@babel/polyfill爲當前環境提供一個墊片。所謂墊片也就是墊平不一樣瀏覽器或者不一樣環境下的差別。
可是babel@7.4及之後這個墊片被廢棄了。
import "core-js/stable";
import "regenerator-runtime/runtime";
複製代碼
來代替@babel/polyfill。
core-js 在安裝@babel/preset-env的時候已經安裝好了。
npm i regenerator-runtime -D
複製代碼
在app.js裏面引入
import "core-js/stable";
import "regenerator-runtime/runtime";
複製代碼
運行命令
npm run build
複製代碼
useBuiltIns 這個配置屬性能夠解決這個問題。官方文檔的配置實際上是babel@7.4之前的寫法,這也形成了我懵逼了兩天。
屬性值 "usage" | "entry" | false, 默認是 false。
useBuiltIns: 'entry' 其實和import "core-js/stable"; import "regenerator-runtime/runtime";效果是同樣的,表示把全部的轉譯代碼都注入到打包的代碼裏面。可是仍是須要在代碼裏面引入這兩個插件。
useBuiltIns: 'usage' 表示把代碼裏面須要用到的轉譯代碼注入到打包的代碼裏面。就不須要引入core-js/stable了。可是regenerator-runtime/runtime仍是須要繼續引入。
{
test: /\.js$/, // 正則匹配,全部的.js文件都使用這個規則進行編譯
exclude: /node_modules/, // 排除的文件夾。這個文件夾裏面的的文件不進行轉譯
loader: "babel-loader", // 轉譯的插件
options: { // 轉譯的規則
presets: [ //轉譯器配置
[
"@babel/preset-env", {
useBuiltIns: "usage"
}
]
],
plugins: [] // 轉譯插件配置
}
},
複製代碼
運行打包命令
npm run build
複製代碼
打包報錯了
{
test: /\.js$/, // 正則匹配,全部的.js文件都使用這個規則進行編譯
exclude: /node_modules/, // 排除的文件夾。這個文件夾裏面的的文件不進行轉譯
loader: "babel-loader", // 轉譯的插件
options: { // 轉譯的規則
presets: [ //轉譯器配置
[
"@babel/preset-env", {
useBuiltIns: "usage",
corejs: 3
}
]
],
plugins: [] // 轉譯插件配置
}
},
複製代碼
運行打包命令
npm run build
複製代碼
打包的文件中有21個promise。
這樣作的好處就是使用哪一種es語法就引入哪一種轉譯器,避免代碼過大。爲何還須要繼續引入regenerator-runtime/runtime呢?由於它的代碼太少了,@babel/preset-env沒有像corejs同樣進行配置。若是不引入async、await就不能使用了。
動態 polyfill
polyfill.io是動態polyfill解決方案最好的方法。
用最新的Chrome打開polyfill.io/v3/polyfill…
去除useBuiltIns配置
<script src="https://cdn.polyfill.io/v3/polyfill.min.js"></script>
複製代碼
後面我又用vivo Y13手機, 14年的安卓4.2.2手機測試了一下。是能夠用的,es七、es6均可以正常運行。
對於最新的 safari 瀏覽器來講,不須要任何 polyfill,因此返回的內容爲空。對於 iie7瀏覽器 來講,須要 URL 對象的 polyfill,因此返回了對應的資源。
babel-loader還有不少配置不少坑,遇到就查文檔或者google吧。
代碼內容詳見demo6
樣式loader,這些都是官方提供的樣式loader。
好比 使用less做爲樣式語法。 首先安裝style-loader css-loader。
npm i style-loader css-loader -D
複製代碼
less-loader文檔裏面顯示須要安裝
npm install --save-dev less-loader less
複製代碼
body{
color: lawngreen;
}
.logo{
background: #f60;
height: 400px;
width: 400px;
background-repeat: no-repeat;
transition: all 1s;
display: flex;
}
.logo:hover{
height: 600px;
width: 600px;
transform: translateY(60px);
}
複製代碼
在app.js 裏面引入
import './src/assets/css/base.less';
複製代碼
運行命令
npm run dev
複製代碼
less文件裏面的transition和transform都是css3的樣式,若是想自動的生成帶前綴的代碼則須要postcss-loader,也須要postcss-loader的一個插件autoprefixer
安裝依賴
npm i autoprefixer postcss-loader -D
複製代碼
更改配置
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer")({
browsers: [
'last 10 Chrome versions',
'last 5 Firefox versions',
'Safari >= 6',
'ie> 8'
]
})
]
}
},
複製代碼
npm run dev
複製代碼
home.less裏面的代碼並無進行css3的轉化。這時咱們須要配置在 css-loader 中使用 importLoaders 屬性。
以前一直運行的是開發環境,咱們運行一下生產打包命令
npm run build
複製代碼
打包後並無css文件。 把代碼放入服務器或者使用http-server起一個本地的服務器。
這時咱們須要引入mini-css-extract-plugin進行css代碼的抽離,以及打包插件optimize-css-assets-webpack-plugin在打包的時候進行css代碼壓縮。
npm i mini-css-extract-plugin optimize-css-assets-webpack-plugin -D
複製代碼
按照官方的語法進行配置
npm run build
複製代碼
css的代碼已經被抽離了而且壓縮了。
查看官網有關於HMR解釋。
模塊熱替換(HMR - Hot Module Replacement)功能會在應用程序運行過程當中替換、添加或刪除模塊,而無需從新加載整個頁面。
按照官方的實例。 首先更改devServer的配置,設置hot屬性爲true。
由於設置模塊熱加載是開發環境須要的。因此更改webpack.dev.conf.js的配置。
plugins:[
new webpack.HotModuleReplacementPlugin()
]
複製代碼
因爲mini-css-extract-plugin不支持HMR,因此在開發環境繼續使用style-loader。 如今css的HMR已經配置好了。
{
test: /\.(png|jpg|gif)$/,
use: [{
// 須要下載file-loader和url-loader
loader: "url-loader",
options: {
limit: 5 * 1024, //小於5kb將會已base64位圖片打包處理
// 圖片文件輸出的文件夾
outputPath: help.assetsPath("images"),
name: '[name].[ext]'
}
}]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
outputPath: help.assetsPath("fonts")
}
},
複製代碼