您好,登錄后才能下訂單哦!
這篇文章主要介紹webpack與SPA實踐之管理CSS等資源的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
前言
在學習使用webpack時,我們需要明白無論它怎么設計,它的工作原理、流程是什么,最根本的它處理的還是HTML文檔中的HTML標簽、JavaScript、CSS、圖片等資源,而且最終的處理結果依然必須是一個HTML文檔,包括DOM、JavaScript、CSS,而CSS在文檔中的存在方式,有三種:行內樣式,內聯樣式,外鏈樣式,行內樣式使用方式早已不推薦,所以webpack處理CSS方式也就兩種:
內聯樣式: 以<style>標簽方式在HTML文檔中嵌入樣式;
外鏈樣式: 打包生成CSS文件,通過<link>標簽引入樣式;
webpack與CSS
我們知道,webpack本質是只能處理JavaScript的,而對于其他資源,需要使用加載器和插件將其處理成JavaScript模塊,然后進行模塊依賴管理。webpack提供style-loader和css-loader兩個加載器支持我們模塊化CSS,因此可以在其他模塊內直接引入。
安裝
npm install --save-dev style-loader css-loader
配置
在webpack配置文件的模塊加載器選項中添加如下配置:
module: { loaders: [ { test: /\.css$/, loader: "style-loader!css-loader" } ] }
當然為了方便使用引用路徑,還可以配置路徑片段別名:
alias: { styles: path.resolve(__dirname, 'src/styles/') }
此時,import 'styles/index.css';
等同于使用相對路徑,如import '../src/styles/indx.css';
使用
配置好以后,假如我們在styles目錄下創建了一個index.css文件,現在可以在JavaScript文件中直接引入該CSS: import 'styles/index.css'; 或 require('styles/index.css');
css內容如下:
html, body { width: 100%; height: 100%; } .container { color: red; }
頁面展示如圖:
內聯樣式
前面提到了webpack處理CSS的方式有兩種,第一種是以內聯方式在頁面<head>標簽內動態插入<style>內聯樣式,這種方式也是webpack的默認處理方式,只需要簡單配置如下加載器:
{ test: /\.css$/, exclude: /node_modules/, loader: 'style-loader!css-loader' // or // loaders: ['style-loader', 'css-loader'] }
WEBPACK加載器解析順序
如上面代碼所示,無論是字符串語法style-loader!css-loader
,亦或是數組語法['style-loader', 'css-loader']
,webpack解析規則都是從右至左,依次解析并執行加載器處理文件,前一加載器處理的輸出就是下一加載器處理的輸入,直到最后加載器處理完成;此處即webpack先調用css-loader加載器處理css文件,然后將處理結果傳遞給style-loader加載器,style-loader接受該輸入繼續處理。
CSS-LOADER
我們已經反復強調,webpack只能處理JavaScript,所以對于其他諸如css或圖片等資源需要使用加載器將其轉換輸出為JavaScript模塊,webpack才能繼續處理。
css-loader加載器的作用就是支持我們像使用JavaScript模塊一樣在JavaScript文件中引用CSS文件,如require ('./index.css'),所以你可以認為其作用是將CSS文件轉換成JavaScript模塊,于是我們可以直接通過引入JavaScript模塊的方式直接引用。
參數
css-loader有兩個常用參數:
modules: {boolean}指定是否使用CSS模塊(如:local和:global設置局部或全局樣式規則),默認是false,開啟設置如css-loader?modules;
importLoaders: {number}指定css-loader加載器之前使用的加載器數量,默認是0,設置如css-loader?importLoaders=1;
STYLE-LOADER
無論webpack怎么處理CSS文件,最終都需要將其輸出到頁面,才能實際使用該CSS規則,style-loader加載器就是將CSS以內聯方式插入到頁面文檔,即:針對每一個輸入(通過require引入,使用css-loader轉換為JavaScript模塊,傳遞給style-loader作為輸入),style-loader在頁面<head>標簽內插入一個<style>標簽,該標簽內樣式規則即此輸入內容,如下實例:
外鏈樣式
當然,我們并不總是希望所有樣式都以內聯方式存在頁面中,很多時候我們也希望通過外鏈方式使用樣式表,特別是樣式規則較多的時候,webpack開發者們當然考慮了這樣的需求。
webpack提供的style-loader
加載器默認是以內聯方式將樣式插入文檔,我們需要使用webpack extract-text-webpack-plugin
插件以實現輸出單獨CSS文件。
EXTRACT TEXT PLUGIN
安裝
首先安裝該插件:
npm install --save-dev extract-text-webpack-plugin
配置
然后添加如下配置:
var ExtractTextPlugin = require('extract-text-webpack-plugin'); ... module: { loaders: [ { test: /\.css$/, exclude: /node_modules/, // 老版本 loader: ExtractTextPlugin.extract('style-loader', 'css-loader') loader: ExtractTextPlugin.extract({ fallback:'style-loader', use: 'css-loader' }) } ] }, plugins: [ // 生成獨立css文件 new ExtractTextPlugin({ filename: 'css/[name].css' }) ]
運行webpack命令,我們會看到在dist/css/文件夾下生成相應的CSS文件。
參數
filename {String | Function}
Extract Text Plugin為每個入口生成一個CSS文件,所以對于多入口項目需要指定filename參數[name]或[id]或[contenthash]生成唯一識別文件名;
disable {Boolean}
禁用此插件;
allChunks {Boolean}
allChunks: true;時指定從所有模塊中抽取CSS輸出至單獨CSS文件,包括異步引入的額外模塊;此插件默認是只抽取初始模塊內引入的CSS;
extract方法
該方法可以以參數指定加載器,然后接受該加載器的輸出,進行處理。需要在加載器和插件配置中同時聲明相關配置,才能實現效果;在加載器配置中調用其extract方法傳入通常以下兩個參數:
1. use: 將CSS轉換成模塊的加載器;
2. fallback: 對于不被抽取輸出至單獨CSS文件的CSS模塊使用的加載器,上例中`style-loader`即說明以內聯方式使用,該加載器通常在`allChunks: false`時處理額外的模塊;
FILENAME與OUTPUT
在上一篇介紹了輸出文件配置output相關內容,其中:
output.path是webpack處理文件后輸出的路徑,對于CSS文件輸出依然適用,即CSS文件也將輸出至該目錄;
output.publicPath是指瀏覽器訪問資源時的相對基礎路徑,規則是: output.publicPath + output.filename;
你可以看到在本系列文章實例中filename都添加了前綴目錄,如css和scripts,你可能看到很多項目是不添加的,但文件入口較多時建議分類型目錄輸出,而且需要記得在瀏覽器訪問資源時也需要添加該目錄層級。
CSS預處理器
通常在開發較復雜的應用時,我們都會選擇一種CSS的強化輔助工具,以更高效,更方便的使用CSS開發應用樣式,這些拓展工具就是所說的CSS預處理器.
CSS預處理器(preprocessors)在CSS語法的基礎上增加了變量 (variables)、嵌套 (nested rules)、混合 (mixins)、導入 (inline imports) 等高級功能,令CSS更加強大與優雅,有助于更好地組織管理樣式文件,以及更高效地開發項目。
目前最常見的CSS預處理器有LESS,SASS,Stylus,個人用過的是前兩種,使用SASS的還是居多。
SASS
安裝
npm install --save-dev sass-loader
安裝sass-loader以后會發現,package.json中多了一個node-sass依賴,這是使用SASS必須的。
配置
然后添加以下配置:
{ test: /\.s[ac]ss$/, exclude: /node_modules/, loader: 'style-loader!css-loader!sass-loader' }
如上,配置中傳遞了三個加載器,相對于前文處理CSS文件的加載器,在最后面多了一個sass-loader,首先加載sass-loader加載器處理SASS文件成CSS代碼,然后繼續按照前文描述流程處理CSS文件。
EXTRACT TEXT PLUGIN
和處理CSS文件一樣,上述配置最終通過style-loader將轉換后的CSS代碼內聯到頁面,我們需要使用Extract Text Plugin生成單獨CSS文件,以外鏈方式引用:
{ test: /\.s[ac]ss$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract({ fallback:'style-loader', use: [ 'css-loader', 'sass-loader' ] }) } ... // 生成獨立css文件 new ExtractTextPlugin({ filename: 'css/[name].css' })
CSS后處理器
前面講到CSS預處理器,如SASS,他們提供對CSS的拓展,包括語法拓展,高級特性拓展,如嵌套,變量,自動處理添加屬性前綴等,使得我們可以以其定義的語法與模板方式更高效的編寫CSS,然而這些預處理器都是另外對CSS進行拓展,各自定義了語法和模板,其處理流程是對代碼進行解析處理,然后轉換成CSS代碼。
不同預處理器有各自的定義和規范,假如你需要從LESS轉到SASS,源代碼轉換成本和學習成本頗高,而接下來要介紹的CSS后處理器并沒有這個問題。
不同于預處理器預定義好一個語法和模板,然后對按照該語法和模板編寫的代碼進行處理轉換成CSS,其輸入是自定義語法文件,輸出是CSS代碼;后處理器(postprocessor)是對原生CSS代碼根據配置進行處理,其輸入輸出依然是CSS代碼。
POSTCSS
現在最受歡迎的CSS后處理器,就是postcss:
PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.
PostCSS是一個使用Js插件轉換樣式的根據,插件支持拓展CSS,如變量,混合,CSS屬性語法兼容,行內圖片等等功能。
特性
不同于SASS提供一個功能性拓展工具,postcss更多的是提供一個CSS高效開發工具解決方式,其本身只包含CSS解析器只能將CSS處理成一棵抽象語法樹(AST),同時提供一個豐富的CSS節點樹API,可以對語法樹進行操作,另外它有一個高拓展性的插件系統支持我們通過引入不同插件對CSS進行處理,一個插件的輸出還可以是下一個插件的輸入,更值得一提的是,這些插件都是JavaScript插件,前端開發者們很容易就能根據項目需求定制自己的插件,所以可以總結幾點一以下特性:
postcss只處理CSS,概念簡潔;
提供高拓展性的插件系統支持按需引入不同插件,實現不同處理;
使用JavaScript插件,開發者可以很方便定制項目插件;
提供CSS節點樹API,可以高效的進行CSS處理;
安裝
在webpack中使用,需要先安裝對應加載器:
npm install --save-dev postcss-loader
插件
postcss目前有200+插件,足夠滿足絕大部分項目開發需求,可以查看postcss插件,我們介紹幾個主要使用的插件。
Autoprefixer
回顧一下在預處理器中,如果我們需要為CSS代碼添加屬性前綴,需要這么實現呢?對于Sass,我們通常使用mixin,即混合宏,處理CSS屬性前綴,如:
// 定義 @mixin prefix-animation($animation-name){ animation:$animation-name; -webkit-animation:$animation-name; } // 使用 body{ @include prefix-animation(loading .5s linear infinite); }
如上,我們需要按照定義的語法和模板:先定義一個mixin,然后通過@include方式使用,最后才能輸出添加前綴的CSS代碼,當代碼越來越多時,我們需要定義的mixin也會越來越多,而且不同預處理器定義的語法和模板都有差異,學習成本、轉換成本都很可能令人難以接受。
那么postcss插件怎么處理的呢?postcss提供了Autoprefixer插件處理CSS屬性前綴:
Autoprefixer插件基于Can I Use的數據,對CSS規則進行前綴處理。
安裝
首先還是要安裝Autoprefixer:
npm install --save-dev autoprefixer
配置
添加如下配置:
module: { loaders: [ { test: /\.css$/, exclude: /node_modules/, loaders: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { plugins: [ require('autoprefixer')({ browsers: ['last 2 versions'] }) ] } } ] } ] }
如上,我們知道postcss是一個樣式開發解決方案,其特定功能需要引入插件實現,上例中在指定postcss-loader加載器時為其設置了插件配置autoprefixer;當然webpack還支持直接設置一個postcss配置文件,然后在項目根目錄創建postcss.config.js配置文件,內容格式如下:
module.exports = { plugins: [ require('autoprefixer')({ browsers: ['last 2 versions'] }) // or just require('autoprefixer') ] }
使用autoprefixer插件時可選傳入browsers參數,可以設置添加前綴的適配范圍,詳細可查閱browsers配置說明。
混合使用CSS預處理器與后處理器 – PreCSS
也許你迫不及待想在項目中引入postcss,又希望能繼續使用CSS預處理器語法,而且需要保證以前按照某預處理器預定語法和模板(如SASS)編寫的源代碼繼續穩定使用,不需要太多的遷移和學習成本,可以做到嗎?當然可以,可以使用預處理器PreCSS插件包,另外我們需要安裝一個postcss的scss解析器,因為postcss默認只包含一個CSS解析器,postcss配置文件更新如下:
module.exports = { parser: require('postcss-scss'), plugins: [ require('autoprefixer')({ browsers: ['last 2 versions'] }), require('precss') ] }
webpack配置文件更新配置:
modules: { loaders: [ { test: /\.s?[ac]ss$/, exclude: /node_modules/, // or 內聯方式 loader: 'style-loader!css-loader!postcss-loader' loader: ExtractTextPlugin.extract({ fallback:'style-loader', use: [ 'css-loader', 'postcss-loader' ] }) } ] }
可以看到文件匹配規則,修改為/\.s?[ac]ss$/,可以匹配包括.sass, .scss, .css樣式文件;在css-loader加載器之前添加了postcss-loader加載器(webpack加載器解析順序為從右至左)。
當然你可以不使用precss,依然使用sass-loader,則只需要修改配置:
loader: 'style-loader!css-loader!postcss-loader!sass-loader'
對于如下SCSS代碼:
$column: 200px; .menu { display: flex; width: calc(4 * $column); }
轉換生成如下CSS代碼:
.menu { display: -webkit-box; display: -ms-flexbox; display: flex; width: calc(4 * 200px); }
處理圖片與字體文件
對于一個應用而言,除了需要開發HTML、CSS、JavaScript,通常還好使用到圖片,字體文件,配置文件等諸多資源,那么前端工程化流程也就必然需要對這些資源進行處理與優化,最典型的說處理圖片和字體文件。
在Grunt或Gulp中,我們對圖片和字體文件的處理通常是將其從源目錄壓縮優化處理后輸出至輸出目錄,通常是以文件目錄整體進行處理,每次構建時,對所有資源,包括未使用的圖片均進行處理,效率是有局限的;而webpack中一切資源文件都可以處理成模塊,然后在編譯時管理模塊依賴,可以做到只處理存在依賴的資源(即,使用了的資源)。
圖片與字體
當我們在Js模塊中引入CSS文件時,其中樣式規則中的背景圖片,字體文件如何處理呢?webpack只能管理模塊化的東西,需要將其模塊化,然后使用webpack管理依賴,webpack提供了file-loader加載器:
File Loader
Instructs webpack to emit the required object as file and to return its public url.
通知webpack將引入的對象輸出為文件并返回其公開資源路徑。
配置
module: { loaders: [ { test: /\.(png|svg|jpe?g|gif)$/, loader: [ 'file-loader' ] } ] }
說明
當我們在js文件中import Image from '../images/test.png'或在CSS文件中url('../images/test.png')時,file-loader將處理該圖片并在output.path目錄下輸出文件,然后將../images/test.png路徑替換成該輸出文件路徑。
注,對于html中引用的圖片,需要使用[html-loader]加載器處理(http://npm.taobao.org/package/html-loader)。
參數
emitFile: 是否輸出文件;
name: 指定輸出文件的文件名,有幾個可用內置變量:
[name]: 引用資源的名稱;
[path]: 引用資源的相對路徑;
[ext]: 資源拓展名;
[hash]: 資源內容的hash值,默認使用md5算法計算得到,可以指定長度值,如[hash:7]表示返回hash值前7個字符;
[hashType:hash:digestType:length]: 指定hash值計算算法類型和摘要類型,及摘要長度,如sha512:hash:base64:7表示使用sha512加密算法計算hash值并且返回7個字符的base64編碼字符
實例
在配置時可以指定參數:file-loader?name=[name].[ext]?[hash:8]
或者以配置對象方式:
{ test: /\.(png|svg|jpe?g|gif)$/, loaders: [ // 'file-loader?name=[path][name].[ext]?[hash:8]' { loader: 'file-loader', query: { name: '[path][name].[ext]?[hash:8]' } } ] }
對于CSS源代碼:
.wrapper { font-size: 18px; background: url('../images/test.png') no-repeat 0 0; }
輸出CSS代碼如下:
.wrapper { font-size: 18px; background: url(assets/images/test.png?59427321) no-repeat 0 0; }
assets為output.publicPath指定值,images/test.png?59427321為配置文件中指定的name模板,在output.path目錄下輸出images/test.png,區別是,不會攜帶?后的參數。
另外,你也可以在js模板中這樣使用:
<img src={imgSrc} /> ... import imgSrc from 'path/xxx.png';
Url Loader
你可能會發現前面并沒有安裝file-loader,因為有更好用的加載器url-loader,url-loader加載器是file-loader的升級版,他們唯一的不同之處在于:
url-loader可以通過limit參數指定一個尺寸值,加載器會對小于該值的資源處理返回一個Data URL,以base64的方式嵌入HTML或CSS,如url-loader?limit=65000;對于大于該尺寸的資源將使用file-loader處理并且傳遞所有參數。
mimetype
還可以設置mimetype對處理文件進行過濾,如url-loader?mimetype=image/png將只處理png類型的資源。
安裝
npm install --save-dev url-loader
配置
該加載器對于圖片和字體文件資源都適用:
{ test: /\.(png|svg|jpe?g|gif)$/, loaders: [ // 'url-loader?name=[path][name].[ext]?[hash:8]' { loader: 'url-loader', query: { limit: 6000, name: '[path][name].[ext]?[hash:8]' } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, loaders: [{ loader: 'url-loader', query: { limit: 10000, name: '[path][name].[ext]?[hash:8]' } }] }
資源優化
完成以上配置后,已經可以在項目中很方便的引用各自資源了,但是通常我們還需要對圖片字體等文件進行壓縮優化處理,如Grunt中使用的imagemin插件一樣壓縮資源,webpack則提供了相關加載器img-loader。
安裝
npm install --save-dev img-loader
配置
{ test: /\.(jpe?g|png|gif|svg)$/i, loaders: [ 'url-loader?name=[path][name].[ext]?[hash:8]', { loader: 'img-loader', options: { // 根據環境判斷是否啟用資源壓縮 enabled: process.env.NODE_ENV === 'production', gifsicle: { interlaced: false // 替換使用漸進式渲染 }, mozjpeg: { progressive: true, // 創建基準jpeg文件 }, optipng: { optimizationLevel: 4, // 優化級別,0-7,值越大,壓縮越多 }, pngquant: { quality: '75-90', // 壓縮質量,0-100,值越高,質量越高 speed: 3 // 執行速度,0-10,速度過高質量受損,不建議過高 }, svgo: { plugins: [ { removeTitle: true }, // 去除標題信息 { convertPathData: false } // 轉換路徑為更短的相對或決定路徑 ] } } } ] }
以上為常見使用配置,更多詳細配置信息請查看對應說明imagemin文檔,特別注意的是上面使用了process.env.NODE_ENV當前環境變量,只有在生產環境啟用圖片壓縮,因為壓縮過程比較比較耗時,可能會降低開發、調試效率。
數據資源
對于數據類型文件資源,webpack內置支持加載解析.json文件,而其他類型則需要安裝配置相應加載器,如.xml文件,需要安裝并配置xml-loader。
資源管理的思考
在傳統或稍早一點的應用中,我們通常會將所有的圖片,字體等資源放在一個基礎目錄下,如assets/或images,但是對于那些在多項目間重復的插件代碼或資源來說,每一次遷移,我們都得在一大堆圖片,字體資源里尋找出我們需要遷移的資源,這對代碼可重用和其獨立性有一定限制,而且與現在提倡的組件化開發模式也不相符。
webpack對于資源的處理方式給組件化開發提供了很大便利,使得我們以組件為單位,可以在某一組件目錄下存放所有相關的js,css,圖片,字體等資源文件;組件的遷移公用成本很低。不過組件化開發并不是說不需要資源目錄了,一些公用的資源依然放在項目的基礎目錄下。
說明
終于可以松口氣,對于webpack管理CSS、圖片、字體、數據資源的實踐基本總結完成,其實感覺要介紹的還有很多,但是要盡量保證文章思路清晰,語句流暢,而且篇幅不能太長,水平有限,花費較多時間經歷,希望能對讀者有所幫助,后續篇章也會繼續穿插介紹,力爭本系列能較完整、較清晰地描述如何使用webpack開發SPA應用。
以上是“webpack與SPA實踐之管理CSS等資源的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。