logo

江西探域科技有限公司

JiangXi T-Reach Technology Co.Ltd

0791-83889316

媽媽再也不用擔心我不會webpack了

2020-06-03 00:00

 webpack前端工程中扮演的角色越來越重要,它也是前端工程化很重要的一環。本文將和大家一起按照項目流程學習使用wbepack,媽媽再也不用擔心我不會使用webpack,哪里不會看哪里。這是一個由淺入深的文章。

工程化

這里是一個項目工程化,規范化的設置,如果是初次使用webpack的同學還是最后在看這一塊知識

現在vue、react等腳手架都會自動將開發環境使用的webpack的配置文件和生產環境的配置文件分開,將壓縮代碼,添加hash控制版本等操作放在項目上線時運行,這樣避免了在開發階段打包時間過長的問題。比如像這樣,把兩個環境的配置文件分開。

 


下面來看下兩個配置文件的內容(我是用的type 開發react,內容請忽略)
開發環境:

 

 

 

生產環境:

 


可以看到,開發環境增加了幾個插件,這樣做的好處就是更加工程化,規范化,降低開發環境的打包時間,代碼維護性也更高。

 

分開寫配置文件就要涉及到使用命令執行不同的配置文件,我們可以使用npm的腳本命令,我們可以在package.json中找到 s,添加如下命令"build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"

給大家解釋下這個命令的意思

  • NODE_ENV=production 就是將運行環境設置成生產環境

  • webpack --config 就是運行webpack的配置文件

  • ./webpack.production.config.js 是要運行的指定位置的文件,這個路徑是相對根目錄來說的

  • --progress 是編譯過程顯示進程百分比的

如果你不追求規范化和工程化,我們就寫一個配置文件就好,這里沒有硬性要求。下面我們來講webpack的具體配置

開始

在我們對于webpack不是特別熟練的時候,我們可能不會寫全配置文件,往往是用到什么再去添加,下面我們就按照這個步驟徹底學會使用webpack。

module.exports = {     entry: './src/index.js' // 這里是項目入口文件地址     ouput: {         path: __dirname + "/dist", // 這里是項目輸出的路徑,__dirname表示當前文件的位置         filename: "js/"+"[name].js" // 這里是生成文件的名稱,可起你想要的名字     } }

loader

這就是我們最初一個骨架,下面我們再添加一些配置,比如你使用的是react,那么你就需要添加react的相關loader,這里以type 編寫的react為例。

module.exports = {     entry: './src/index.js' // 這里是項目入口文件地址     ouput: {         path: __dirname + "/dist", // 這里是項目輸出的路徑,__dirname表示當前文件的位置         filename: "js/"+"[name].js" // 這里是生成文件的名稱,可起你想要的名字     },     module: {         rules: [             { test: /\.tsx?$/, loader: "awesome-type -loader" },             { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }         ]     }, }

css/css預處理語言(less、sass、stylus)

webpack是將一個個文件分拆成一個個模塊(module)來進行編譯打包的,我們所有的處理文件內容的東西都要放在module里,rules即規則。
rules里面的兩個loader都是編譯.tsx文件及處理錯誤信息的。

在你寫好了組件之后,你需要開始編寫樣式,但無論是css還是使用less、sass等預處理語言,webpack都是無法直接處理的,我們安裝并使用相應的loader。下面以less和css為例。

 {test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader"]}

webpack會按照從右到左的順序執行loader,我們新解析less,之后進行css的打包編譯。如果你不適用less等預處理語言,安裝css-loader和style-loader即可。

  • style-loader 將css插入到頁面的style標簽

  • css-loader 是處理css文件中的url()等

  • less-loader 是將less文件編譯成css

postcss解決css兼容問題

寫到這里我們會突然想到一個點,就是css樣式的兼容性問題,靠人工去寫的話,你心里可能會有一句mmp不值當講不當講,哈哈,我們必須使用postcss來解決這個問題。

postcss是目前css兼容性的解決方案,會自動幫我們加入前綴,以使css樣式在不同的瀏覽器能兼容,這里安裝使用postcss-loader

{ test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader", "postcss-loader"]}

postcss-loader要寫在最后,寫到這你以為就可以了嗎?只能說 too young,postcss解決兼容性問題主要靠的其實是它的插件autoprefixer,我們還需要在根目錄寫一個postcss.config.js的配置文件,如下

module.exports = {     plugins: [         require('autoprefixer')     ] };

寫到這,我們就不用再擔心css兼容性問題了,就想使用babel文件一樣,這個文件會自動解析,我們不需要管它。

svg圖片的使用

我們在開發時,往往會遇到一些圖標圖片在不同情況下會失真,以及資源過多,我們需要減小圖標類圖片的大小,這時我們就需要引入svg,國內可能都會去使用阿里的iconfont庫,從而引入svg圖標,解決上面的問題

我們打開下載的素材文件夾,發現里面有一些.woff、.svg、.eot的文件,我們要想使用svg的圖標還必須依賴這些文件,這時webpack不支持這些文件,我們需要引入新的loader

{ test: /\.(woff|svg|eot|ttf)?$/, loader: "url-loader" }

下面我們就能愉快的使用svg圖標了,不存在失真的情況,同時會很小

webpack-dev-server

寫到這,我們可能不斷的打包webpack了,太麻煩了,于是乎webpack-dev-server應運而生。它是webpack提供的服務器,我們使用npm i webpack-dev-server --save-dev來安裝。
我們其實在命令行中敲擊webpack-dev-server --open就可以開啟,默認是localhost:8080開啟,現在我們不需要在重復使用webpack命令打包,安裝。

值得注意的是,webpack-dev-server打包的文件會存在內存中,所以在index.html中引入文件的時候就要如下,這里是默認輸出文件是bundle.js

<  src="bundle.js">

今天我們不重點講webpack-dev-server,以后我會再寫文章,深入的講解其使用。

可能我們在開發階段只用到了這幾個功能,下面我們來講一下項目上線的準備。

生產環境

優化

壓縮js代碼

我們打包完成的項目往往比較大,包含很多空格,占用了很大空間,這時我們要通過壓縮js來減小文件體積。webpack自帶了UglifyJsPlugin插件來壓縮js代碼,使用如下

plugins: [         new webpack.optimize.UglifyJsPlugin({             compress: {                 warnings: false             }         })     ]

我們的插件統一放在export.modules = {}的plugins里面,它是一個數組,使用插件時new 一個實例即可。這里我們使用到webpack實例,所以要在配置文件頭部引入webpack,即var webpack = require('webpack');

拆分文件

我們在使用的js庫如vue或者react等的時候,webpack會將它們一起打包,react和react-dom文件就好幾百k,全部打包成一個文件,可想而知,這個文件會很大,用戶在首次打開時就往往會出現白屏等待時間過長的問題,這時,我們就需要將這類文件抽離出來。

externals: {         "react": "React",         "react-dom": "ReactDOM"     },

這里我們會用到externals,它和plugins是平級。左側key表示依賴,右側value表示文件中使用的對象。比如在react開發中,我們常常會這樣在文件頭部寫import React from 'react',這里大家可以和上面對號入座下。

這里我們就需要對這個文件進行單獨的引入使用了,在index.html中添加如下代碼

<  src="./node_modules/react/umd/react.xxx.js"> <  src="./node_modules/react-dom/umd/react-dom.xxx.js">

寫到這,我們就已經將文件拆分了。
不過,我們在項目上線的時候不可能會帶有node_modules,所以我們就需要使用一個copy插件將react和react-dom文件復制出來

 new CopyWebpackPlugin([ // from是要copy的文件,to是生成出來的文件             { from: "node_modules/react/umd/react.xxx.js", to: "js/react.min.js" },             { from: "node_modules/react-dom/umd/react-dom.xxx.js", to: "js/react-dom.min.js" }             { from: "public/favicon.ico", to: "favicon.ico" }         ])

這樣我們的index.html文件中就要寫成下面這種形式

 

 

拆分css

我們也可以將css文件單獨拆分出來,這樣的好處就是打包的css文件我們可以放到cdn上,然后緩存到瀏覽器客戶端中。這樣就盡可能的減小文件的體積,以及不必要的資源重新加載,浪費帶寬。

我們要先安裝插件

npm install extract-text-webpack-plugin --save-dev

配置文件添加對應配置

var ExtractTextPlugin = require("extract-text-webpack-plugin");

plugins里面添加插件

new ExtractTextPlugin("styles.css")
下面是具體的使用

module.exports = {     // entry和output自動省略     module: {       loaders: [{         test: /\.css$/,         loader: ExtractTextPlugin.extract('style-loader',         'css-loader!postcss-loader') // 這里我目前使用less還沒有成功       }]     },     postcss: function() {       return [autoprefixer, cssnext, precss, cssnano]     },     plugins: [       new ExtractTextPlugin('./css/[name].min.css') // 生成到css文件夾下     ]   }

webpack會將所有引用到的css文件打包,最終生成./css/[name].min.css文件。

圖片處理

這里對圖片進行 64進行轉碼同樣是減小資源的體積

安裝 url-loader

npm install url-loader --save-dev

在modules的rules里面添加

{     test: /\.(png|jpg)$/,     loader: 'url?limit=8192&name=images/[hash:8].[name].[ext]' }

limit 設置一個閾值,小于這個值得圖片就會自動啟用 64 編碼的圖片,大于這個值的圖片會打包到name 這參數對應的路徑,圖片名稱就會包括8位md5編碼 name 對應文件本來名稱,ext 對應擴展名

瀏覽器緩存資源

我們的后臺會給資源設置Cache-Control: max-age=秒替代,來對資源進行緩存時間的設置,這使得我們在刷新頁面之后會去緩存中加載資源,但是存在一個問題,就是,一旦我們更新版本之后,客戶沒有去清除緩存,同時緩存還沒有過期的情況下,就無法加載到最新的資源。這時我們就需要hash值來進行版本控制

我們通常這樣做

output: {         path: __dirname + "/dist",         filename: "[name][hash].js"     }

給輸出文件加上[hash]來添加hash值,這樣就可以做到用戶加載html里會去加載對應hash值得打包文件,比如下面這樣

<  type="text/ " src="main3d1cb903f77dad5737e9.js">

打包出來的js文件是這樣

 


這樣就能解決這個問題了。

 

還有最后一項

我們不可能每次都去手動復制一個index.html到打包好的dist文件中,我們會使用一款插件html-webpack-plugin
它可以自動添加html文件到dist文件中,同時它會自動添加js文件并帶有hash值

引入插件

var HtmlWebpackPlugin = require('html-webpack-plugin');

使用插件

new HtmlWebpackPlugin({             template: path.join(__dirname, 'src/index.tmpl.html'),             filename: 'index.html'         })

這里給大家解釋下,template是模板,我們在很多情況下,生產環境和開發環境不同,導致index.html引入的資源路徑不同,這是為了改來改去,我們可以創建一個模板,它指定編譯時我們copy的index.html文件。filename是最終生成的文件名。

模板文件如下

       <  charset="UTF-8">     <  rel="icon" href="favicon.ico">     < >Projection-Web      
 
 <  src="js/react.min.js"> <  src="js/react-dom.min.js">  

生成的index.html文件如下

       <  charset="UTF-8">     <  rel="icon" href="favicon.ico">     < >Projection-Web      
 
 <  src="js/react.min.js"> <  src="js/react-dom.min.js"> <  type="text/ " src="js/main3d1cb903f77dad5737e9.js"> 

下面是我打包編譯的dist文件夾內容

 


下面是生產環境的配置文件(部分)

 

var CopyWebpackPlugin = require("copy-webpack-plugin"); var HtmlWebpackPlugin = require('html-webpack-plugin'); var webpack = require("webpack"); var path = require('path'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = {     entry: "./src/index.tsx",     output: {         path: __dirname + "/dist",         filename: "js/"+"[name][hash].js"     },     devtool: "source-map",     resolve: {         extensions: [".ts", ".tsx", ".js", ".json"]     },     module: {         rules: [             { test: /\.tsx?$/, loader: "awesome-type -loader" },             { enforce: "pre", test: /\.js$/, loader: "source-map-loader" },             { test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader", "postcss-loader"] },             { test: /\.(woff|svg|eot|ttf)?$/, loader: "url-loader" }         ]     },     externals: {         "react": "React",         "react-dom": "ReactDOM"     },     plugins: [         new CopyWebpackPlugin([             { from: "node_modules/react/dist/react.js", to: "js/react.min.js" },             { from: "node_modules/react-dom/dist/react-dom.js", to: "js/react-dom.min.js" },             { from: "index.html", to: "index.html" },             { from: "public/favicon.ico", to: "favicon.ico" }         ]),         new HtmlWebpackPlugin({             template: path.join(__dirname, 'src/index.tmpl.html'),             filename: 'index.html'         }),         new webpack.optimize.UglifyJsPlugin({             compress: {                 warnings: false             }         })     ] };

學好webpack,是一名現代前端開發工程師的基本素養。后續還會深入webpack,謝謝大家

熱點資訊

我公司技術保障助力第六屆江西省互聯網+大賽圓滿落幕

2020-08-28 00:00

2020年新冠疫情對IT行業的影響

2020-03-22 00:00

國家發布 AI 的三年發展計劃(2018年-2020)

2018-01-06 00:00

欧美成人性生活天天看高清影 - 视频 - 在线观看 - 影视资讯 - 品善网