webpack 在現在的前端開發中,算是不可繞過的一個工具吧。特別是在開發SPA應用的時候,不管是開發環境,仍是打包上線,都十分依賴webpack。javascript
win10
css
node -v: 10.15.0
html
npm -v: 6.4.1
前端
Let's go。vue
進入到工做目錄,而後建立項目java
mkdir spa-webpack-demo
複製代碼
初始化node
npm init -y
複製代碼
先來體驗下 webpack4
的 0配置
:webpack
安裝 webpackgit
npm i -D webpack
複製代碼
安裝好 webpack 依賴後,建立 src 文件夾,並在 src 中新建一個 index.js
。github
mkdir src
cd src
type nul > index.js
複製代碼
修改 package.json
,在 scripts
選項中,添加兩個命令:
"dev": "webpack --mode=development",
"prod": "webpack --mode=production"
複製代碼
好,完事了。接下來跑命令行,測試一下
npm run dev
複製代碼
正常狀況下,控制檯會有一段以下提示,由於 webpack
命令須要依賴 webpack-cli
,咱們安裝便可
Do you want to install 'webpack-cli' (yes/no): yes
複製代碼
webpack-cli
安裝完成以後,會自動繼續跑咱們的 npm run dev
指令,便可看到項目中多了一個 dist 目錄,並且多了一個 main.js
。
接下來繼續嘗試 npm run prod
,能夠看到 dist/main.js
已被壓縮。
這就是 webpack
號稱的零配置,主要的工做就是定義了默認的entry
路徑src/index.js
,定義了默認的output
路徑dist/main.js
,而後加了一個mode
參數,根據mode
參數的不一樣幫咱們添加一些預置的打包規則。
上述的流程裏,只是體驗了一把零配置的感受,連html文件都沒有,這裏開始加上。
在根目錄新建 index.html
,隨便編寫點內容
type nul > index.html
複製代碼
說處處理 html
文件,確定少不了 html-webpack-plugin
, 安裝它
npm i -D html-webpack-plugin
複製代碼
而後再項目根目錄
新建一個 webpack.config.js
,webpack會自動使用它
type nul > webpack.config.js
複製代碼
webpack.config.js
的內容以下
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
module: {
rules: []
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html'
})
]
}
複製代碼
執行npm run dev
,便可看到 dist
文件夾多了個index.html
,這個index.html
自動引入了打包後的dist/main.js
。
index.html
是生成了,可總不能每次手動打開它在瀏覽器裏面預覽吧, webpack 官方推薦咱們用 webpack-dev-server
作服務器,安裝它
npm i -D webpack-dev-server
複製代碼
安裝成功後, 修改webpack.config.js
,添加 devServer
選項 和 webpack.HotModuleReplacementPlugin
插件。
對於文件中已經添加過的內容,後面我都會用註釋表示。
const path = require('path');
const webpack = require('webpack');
function resolve(dir) {
return path.join(__dirname, './', dir)
}
module.exports = {
// module - 略
devServer: {
contentBase: resolve('dist'), // 根目錄
hot: true, // 是否開啓熱替換,無須手動刷新瀏覽器
port: 8081, // 端口
open: true, // 是否自動打開瀏覽器
noInfo: true // 不提示打包信息,錯誤和警告仍然會顯示
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// HtmlWebpackPlugin - 略
]
}
複製代碼
而後修改 package.json
scripts
的 dev
選項
"dev": "webpack-dev-server --mode=development",
複製代碼
注意:當 devServer
的 hot
參數爲true
時,記得要在插件裏添加new webpack.HotModuleReplacementPlugin()
, 或者你能夠在命令行中帶上hot
參數,這樣就不須要本身再往plugins
中添加插件了。
"dev": "webpack-dev-server --hot --mode=development"
複製代碼
而後npm run dev
,就能夠嘗試靜態資源
熱替換功能了。
首先咱們要清楚一點,webpack 它自己是不知道應該如何處理靜態資源的,可是它提供了loader
和plugin
機制。
loader
的做用,顧名思義:加載器,就是匹配到的靜態資源,都要通過loader
的內部處理,再返回處理以後的結果。我以爲,loader
像是一個攔截器。
說到js,咱們會想到 babel-loader
,babel-loader
是幹嘛的?常規操做是,將匹配到的js文件
的ES6代碼 根據 babelrc文件內的配置
編譯成對應的 ES5代碼。
咱們這裏先添加一個.babelrc
文件
新增.babelrc
文件
type nul > .babelrc
複製代碼
編輯 .babelrc
內容
{
// 預設置,告訴Babel要轉換的源碼使用了哪些新的語法特性
// targets, useBuiltIns 等選項用於編譯出兼容目標環境的代碼
// 其中 useBuiltIns 若是設爲 "usage"
// Babel 會根據實際代碼中使用的 ES6/ES7 代碼,以及與你指定的 targets,按需引入對應的 polyfill
// 而無需在代碼中直接引入 import '@babel/polyfill',避免輸出的包過大,同時又能夠放心使用各類新語法特性。
"presets": [
["@babel/preset-env", {
// modules 是否 將 ES6 的 import/export模塊化 轉爲 babel 的 CommonJs 規範模塊化
"modules": false,
"targets": {
// "> 1%" : 支持市場份額超過1%的瀏覽器,
// ""last 2 versions"": 支持每一個瀏覽器最後兩個版本
// "not ie <= 8": 在以前條件的瀏覽器中,排除 IE8 如下的瀏覽器
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
},
"useBuiltIns": "usage"
}]
],
// 所用插件
// transform-runtime 插件表示無論瀏覽器是否支持ES6,只要是ES6的語法,它都會進行轉碼成ES5
// 這個是須要優化的
"plugins": ["@babel/plugin-transform-runtime"]
}
複製代碼
安裝 babel
依賴,注意:
babel 7+ 已經廢棄了presets 中 stage-x 的用法,改成在plugins中添加。而且應用了npm scope包,代碼所有在 @babel 中,避免之前那種 babel-preset-xxx, babel-plugin-xxx 的用法
最新的 babel-loader 版本是8+,須要依賴 babel-core 版本7+,包名爲 @babel/core, 版本6+的包名爲 babel-core
。
再分析上面的 .babelrc 文件,它用到了@babel/preset-env, @babel/plugin-transform-runtime, 這些依賴都要咱們安裝好
若是使用了 @babel/preset-env,則不支持在 plugins 中 添加 stage-x
npm i -D babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime
複製代碼
談到css,咱們就應該 想到 style-loader
和 css-loader
。先安裝它們
npm i -D style-loader css-loader
複製代碼
再安裝 url-loader
用於解析靜態資源,如圖片,字體等
npm i -D url-loader
複製代碼
而後修改 webpack.config.js
的rules
, 添加以下代碼
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src'),
resolve('node_modules/webpack-dev-server/client')
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
exclude: [],
options: {
limit: 10000,
name: 'img/[name].[hash:7].[ext]'
}
}
]
},
// devServer - 略
// plugins - 略
}
複製代碼
vue 就不用裝在 devDependencies 中了。
npm i -S vue
// vue-loader 依賴 vue-template-compiler 和 vue-style-loader
npm i -D vue-loader vue-template-compiler vue-style-loader
複製代碼
修改 webpack.config.js
, 添加 以下代碼
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src')
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 其餘 - 略
]
},
// devServer - 略
plugins: [
// 加在最前面
new VueLoaderPlugin()
// 其餘 - 略
]
}
複製代碼
src 下 新建一個 views 目錄 和 assets 目錄,
我在 assets 目錄下,增長了一個 logo.png 文件
views下建立一個 myTest 組件,myTest/index.vue
, 編輯 index.vue
<template>
<div>
<i class="logo"></i>
</div>
</template>
<script>
export default {
name: 'myTest'
}
</script>
<style scoped>
.logo {
display: block;
margin: auto;
width: 400px;
height: 400px;
background: url(../../assets/logo.png);
}
</style>
複製代碼
src
目錄下新建一個 App.vue
, 內容以下
<template>
<div id="app"> <my-test></my-test> </div> </template>
<script>
import myTest from "./views/myTest/index";
export default {
name: "App",
components: {
myTest
}
};
</script>
複製代碼
編輯 src
目錄下的 index.js
,內容以下:
import Vue from 'vue';
import App from './App';
new Vue({
el: '#app',
render: h => h(App)
})
複製代碼
最後npm run dev
,查看效果。
npm i -D progress-bar-webpack-plugin
複製代碼
修改 webpack.config.js
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// ....
plugins: [
// 其餘 - 略
new ProgressBarPlugin()
]
複製代碼
npm i -D webpack-build-notifier
複製代碼
修改 webpack.config.js
const WebpackBuildNotifierPlugin = require('webpack-build-notifier');
// ....
plugins: [
// 其餘 - 略
new WebpackBuildNotifierPlugin()
]
複製代碼
npm i -D webpack-dashboard
複製代碼
修改 webpack.config.js
const DashboardPlugin = require('webpack-dashboard/plugin');
// ....
plugins: [
// 其餘 - 略
new DashboardPlugin()
]
複製代碼
修改 package.json
"dev": "webpack-dashboard -- webpack-dev-server --mode=development"
複製代碼
這個我使用了,感受效果不是很理想啊,會新開一個窗口,並且還不能滾動查看信息,不清楚是否是哪裏用錯了。
效果如圖:
整個代碼結構如圖:
production
環境,須要使用 mini-css-extract-plugin
和 optimize-css-assets-webpack-plugin
插件,抽離並優化 css 文件production
環境,須要使用 UglifyJsPlugin
插件,壓縮 js 文件,這個插件容許多核編譯production
環境,須要使用 optimization
選項 splitChunks
vue-router
與 vuex
的引入但願本文的流程能幫助到有須要的讀者,另外本文的打包功能實現的比較粗糙,打包速度比較慢,若是看官有啥建議,請在評論下告知下我。
若是有錯誤的地方,還請指出。謝謝閱讀。
代碼地址 spa-webpack-demo