想必大多數人在開發 vue 等 SPA 項目都時候都會直接用 vue-cli
等腳手架開發,一是方便省去了好多配置上的功夫,二是 vue-cli
畢竟是久經考驗較爲成熟的東西,遇到問題也能在網上找到相應解決方案。css
可是,若是咱們要更好地理解腳手架的配置及其構建打包的機制,咱們就有必要從零開始,依葫蘆畫瓢本身配置一個相似於 vue-cli 這樣的項目了。在此,我作了如下簡單配置,請各位大佬批評指正,並誠心但願能獲得大佬的指點,解決文章最後關於 Tree Shaking
致使打包缺失 css 的問題。html
本文主要包括以下配置:前端
webpack-dev-server
本地服務器HtmlWebpackPlugin
生成 htmlCleanWebpackPlugin
清理文件夾loader
及 babel
配置HotModuleReplacementPlugin
熱更新postcss-loader
增長 css 前綴vue SPA
引入及解析vue-router
安裝與使用mini-css-extract-plugin
分離 csspurifycss-webpack purify-css
消除冗餘 cssoptimize-css-assets-webpack-plugin
壓縮 cssterser-webpack-plugin
壓縮 jssplitChunks
提取公共代碼image-webpack-loader
圖片壓縮gZip
加速優化項目源碼:github.com/Michael-lzg…vue
若是對 webpack 基本配置還不瞭解的小夥伴,可查看如下文章
從零開始構建一個 webpack 項目
搭建一個 vue-cli4+webpack 移動端框架(開箱即用)java
廢話很少說,老司機帶你馬上上路。node
webpack-vue-cli
文件夾,npm-init-y
初始化項目npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev
若是 webpack
和 webpack-cli
沒有全局安裝的話,要先全局安裝webpack
├── src // webpack配置文件 |——main.js // 入口文件 ├── static // 項目打包路徑 ├── index.html // 模板html ├── webpack.base.js // 打包基本配置 ├── webpack.dev.js // 本地環境配置 ├── webpack.prod.js // 生產環境配置
index.html
和 main.js
的代碼很少說,直接進入 webpack 配置環節。git
爲了更好的優化打包,咱們將 webpack 的配置分開開發環境和生產環境。github
在 webpack.dev.js
和 webpack.prod.js
,咱們能夠利用 webpack-merge
進行配置的合併。web
而後,咱們在 package.json 定義不一樣環境的打包命令
"scripts": { "dev": "webpack-dev-server --config webpack.dev.js --mode development", "build": "webpack --config webpack.prod.js" }
咱們先來看一下 webpack.base.js
的公共配置,定義好入口文件和出口文件
module.exports = { entry: { index: path.join(__dirname, '/src/main.js'), }, output: { path: path.join(__dirname, '/dist'), //打包後的文件存放的地方 filename: 'js/[name].[hash].js', // 每次保存 hash 都變化 }, }
webpack 提供了一個可選的本地開發服務器,這個本地服務器基於 node.js
構建,因此在 webpack.dev.js
進行配置
const merge = require('webpack-merge') // 引入webpack-merge功能模塊 const common = require('./webpack.base.js') // 引入webpack.common.js module.exports = merge(common, { // 將webpack.common.js合併到當前文件 devServer: { contentBase: './dist', // 本地服務器所加載文件的目錄 port: '8899', // 設置端口號爲8088 inline: true, // 文件修改後實時刷新 historyApiFallback: true, //不跳轉 hot: true, // 熱更新 }, mode: 'development', // 設置mode })
HtmlWebpackPlugin
簡化了 HTML 文件的建立,它能夠根據 html 模板在打包後自動爲你生產打包後的 html 文件。這對於在文件名中包含每次會隨着編譯而發生變化哈希的bundle
。
plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, '/index.html'), // new一個這個插件的實例,並傳入相關的參數 }), ]
至此就搭建好一個乞丐版的 webpack
項目了,你能夠隨意編寫代碼,分別在開發環境和生產環境執行命令查看效果。
loader
可讓 webpack
可以去處理那些非 javaScript
文件(webpack
自身只理解 javaScript
)。loader
能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。
對於 loader
的科普和配置,在這裏不作一一說明,直接奉上代碼,分別是處理樣式,js
和文件的 loader
。
module: { rules: [ { test: /\.css$/, // 正則匹配以.css結尾的文件 use: ['style-loader', 'css-loader'], }, { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'], }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src')], }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]'), }, }, ] }
爲了更方便的配置和優化 babel-loader
,咱們能夠將其提取出來,在根目錄下新建 .babelrc
文件
{ "presets": ["env"] }
在每次構建前清理/dist 文件夾,生產最新的打包文件,這時候就用到 CleanWebpackPlugin
插件了。
plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, '/index.html'), // new一個這個插件的實例,並傳入相關的參數 }), new CleanWebpackPlugin(), // 所要清理的文件夾名稱 ]
HotModuleReplacementPlugin
(HMR)是一個很實用的插件,能夠在咱們修改代碼後自動刷新預覽效果,在開發環境使用。
devServer
配置項中設置 hot: true
HotModuleReplacementPlugin
是 webpack 模塊自帶的,因此引入 webpack 後,在 plugins
配置項中直接使用便可。plugins: [ new webpack.HotModuleReplacementPlugin(), // 熱更新插件 ]
平時咱們寫 css 時,一些屬性須要手動加上前綴,好比-webkit-border-radius: 10px;
,在 webpack 中咱們可讓他自動加上
npm i postcss-loader autoprefixer -D
postcss.config.js
文件module.exports = { plugins: [ require('autoprefixer'), // 引用autoprefixer模塊 ], }
rules: [ { test: /\.css$/, // 正則匹配以.css結尾的文件 use: ['style-loader', 'css-loader', 'postcss-loader'], }, { test: /\.less$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'], }, ]
至此,一個 webpack 項目基本搭建而成,下面介紹 vue 的引用和項目優化。
一、搭建一個相似於 vue-cli
的腳手架,首先咱們來依葫蘆畫瓢,在 main.js
寫上一下代碼
import Vue from 'vue' import App from './App.vue' new Vue({ el: '#app', render: (h) => h(App), })
二、而後在 src 文件夾下新建 APP.vue
<div id="app">SPA項目</div>
三、安裝相關依賴
到這裏,咱們 npm run dev
試一下就報錯了。由於咱們沒有安裝相關依賴,下面咱們下來安裝一下依賴
npm install vue vue-loader vue-template-compiler -D
四、在 webpack 配置 vue-loader
const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', }, ], }, plugins: [new VueLoaderPlugin()], }
一、安裝依賴
npm install vue-router -D
二、在 src 文件夾下新建 router/index
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) const router = new Router({ routes: [ { path: '/', component: () => import('../views/Home.vue'), }, { path: '/admin', component: () => import('../views/admin.vue'), }, ], }) export default router
三、在 main.js 引用
import Vue from 'vue' import App from './App.vue' import router from './router' new Vue({ el: '#app', router, render: (h) => h(App), })
就這樣,一個相似於 vue-cli
的腳手架就搭建好了,你能夠愉快地寫 .vue
文件進行 SPA 開發。
雖然 webpack 的理念是把 css、js 全都打包到一個文件裏,但要是咱們想把 css 分離出來,這裏咱們用到 mini-css-extract-plugin
。對比另外一個插件 extract-text-webpack-plugin
,它有如下優勢:
可是mini-css-extract-plugin
不支持 HMR
,因此咱們只能在生產環境使用它。
一、安裝依賴
npm install mini-css-extract-plugin -D
二、在webpack.prod.js
配置 loader
和 plugin
module: { rules: [ { test: /\.(le|c)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: '../' }, }, 'css-loader', 'postcss-loader', 'less-loader', ] } ] }, plugins: [ new MiniCssExtractPlugin({ filename: "css/[name].[contenthash:8].css", chunkFilename: 'css/[id].[contenthash:8].css' }) ]
分離 css 須要將 css loader
中的 style-loader
替換爲 MiniCssExtractPlugin
有時候咱們 css 寫得多了或者重複了,這就形成了多餘的代碼,咱們但願在生產環境進行去除。
一、安裝依賴
npm i purifycss-webpack purify-css glob -D
二、webpack.prod.js 配置
const path = require('path') const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件 const glob = require('glob') // 引入glob模塊,用於掃描所有html文件中所引用的css module.exports = merge(common, { plugins: [ new PurifyCssWebpack({ paths: glob.sync(path.join(__dirname, 'src/*.html')), }), ], })
咱們但願減少 css 打包後的體積,能夠用到 optimize-css-assets-webpack-plugin
。 一、安裝依賴
npm install optimize-css-assets-webpack-plugin -D
二、webpack.prod.js 配置
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") // 壓縮css代碼 optimization: { minimizer: [ // 壓縮css new OptimizeCSSAssetsPlugin({}) ]
Webpack4.0 默認是使用 terser-webpack-plugin
這個壓縮插件,在此以前是使用 uglifyjs-webpack-plugin
,二者的區別是後者對 ES6 的壓縮不是很好,同時咱們能夠開啓 parallel
參數,使用多進程壓縮,加快壓縮。
一、安裝依賴
npm install terser-webpack-plugin -D
二、webpack.prod.js 配置
const TerserPlugin = require('terser-webpack-plugin') // 壓縮js代碼 optimization: { minimizer: [ new TerserPlugin({ parallel: 4, // 開啓幾個進程來處理壓縮,默認是 os.cpus().length - 1 cache: true, // 是否緩存 sourceMap: false, }), // 壓縮css new OptimizeCSSAssetsPlugin({}), ] }
在用 webpack 打包的時候,對於一些不常常更新的第三方庫,好比 vue 全家桶的一些東西, 咱們但願能和本身的代碼分離開。webpack4 使用 splitChunks
的方法進行配置。
optimization: { // 分離chunks splitChunks: { chunks: 'all', cacheGroups: { vendor: { name: "vendor", test: /[\\/]node_modules[\\/]/, priority: 10, chunks: "initial" // 只打包初始時依賴的第三方 }, } } }
在項目中有些圖片太大影響加載,咱們用 image-webpack-loader
進行壓縮。
一、安裝依賴
npm install image-webpack-loader -D
二、配置 loader
{ test: /\.(png|jpg|svg|gif)$/, use: [ { loader: 'url-loader', options: { esModule: false, limit: 1000, // 限制只有小於1kb的圖片才轉爲base64 outputPath: 'images', // 設置打包後圖片存放的文件夾名稱 name: '[name][hash:8].[ext]' } }, { loader: 'image-webpack-loader', options: { // 壓縮 jpeg 的配置 mozjpeg: { progressive: true, quality: 65 }, // 使用 imagemin**-optipng 壓縮 png,enable: false 爲關閉 optipng: { enabled: false, }, // // 使用 imagemin-pngquant 壓縮 png pngquant: { quality: [0.65, 0.90], speed: 4 }, // 壓縮 gif 的配置 gifsicle: { interlaced: false, }, // 開啓 webp,會把 jpg 和 png 圖片壓縮爲 webp 格式 webp: { quality: 75 } } } ] }
全部現代瀏覽器都支持 gzip
壓縮,啓用 gzip
壓縮可大幅縮減傳輸資源大小,從而縮短資源下載時間,減小首次白屏時間,提高用戶體驗。
gzip 對基於文本格式文件的壓縮效果最好(如:CSS、JavaScript 和 HTML),在壓縮較大文件時每每可實現高達 70-90% 的壓縮率,對已經壓縮過的資源(如:圖片)進行 gzip 壓縮處理,效果很很差。
const CompressionPlugin = require('compression-webpack-plugin') configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { config.plugins.push( new CompressionPlugin({ // gzip壓縮配置 test: /\.js$|\.html$|\.css/, // 匹配文件名 threshold: 10240, // 對超過10kb的數據進行壓縮 deleteOriginalAssets: false, // 是否刪除原文件 }) ) } }
按以上的方式構建項目,在開發環境一直都是順順利利的,然而一執行 npm run build
,打開頁面,發現樣式全都缺失了。打開 dist/css
文件夾,發現三個 css 文件,只有 index.css
有部分文件(是 main.js 引入額初始化樣式,但也是不全的),另外兩個 css 文件則是空空如也,也就是.vue 裏面的樣式全都缺失了。
查看資源,初步判斷爲 webpack4 默認使用 tree-shaking
,會把 在模塊的層面上作到打包後的代碼只包含被引用並被執行的模塊,而不被引用或不被執行的模塊被刪除掉,以起到減包的效果。可是我已經按相關資源在 package.json
配置了 sideEffects
了,可是仍是沒用,實在苦惱!!!
"sideEffects": [ "*.less", "*.css", "*.vue" ]
在此求助於各位大佬,若有遇過相似問題或者知道解決方法的,請不吝賜教,小弟不勝感激!!!
搭建一個 vue-cli4+webpack 移動端框架(開箱即用)
封裝一個toast和dialog組件併發布到npm
從零開始構建一個webpack項目
總結幾個webpack打包優化的方法
總結vue知識體系之高級應用篇
總結vue知識體系之實用技巧
總結vue知識體系之基礎入門篇
總結移動端H5開發經常使用技巧(乾貨滿滿哦!)
關注的個人公衆號不按期分享前端知識,與您一塊兒進步!