webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。javascript
當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。css
mkdir webpack-demo-1
cd webpack-demo-1
npm init -y //生成package.json,而且一路贊成,若是沒啥個性化的內容則省了你一路狂按enter
npm install --save-dev webpack //安裝到開發環境裏面(devDependicies)
複製代碼
touch webpack.config.js
vi webpack.config.js
複製代碼
配置文件內容以下html
const path = require('path');
module.exports = {
entry: './src/index.js', // 這裏應用程序開始執行,webpack 開始打包
output: {
// webpack 如何輸出結果的相關選項
filename: 'bundle.js',//輸出資源塊的名字(asset chunk)
path: path.resolve(__dirname, 'dist') // 全部輸出文件的目標路徑,個人就是./dist/bundle.js
}
};
複製代碼
把當前目錄的src下的index.js打包到了dist目錄下,而且生成了(emmited)一個改頭換面的bundle.js
,裏面的代碼面目全非啊。前端
entry: {
scss: './src/css/main.scss', //對象的鍵名scss 就是輸出文件的name
bundle: './src/js/app.js'
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, 'dist/js')
// publicPath: "/output/"
},
複製代碼
多個入口最好寫成對象的形式,官網說若是寫成了數組,輸出的內容會是數組的第一個。java
上述代碼會在dist/js
目錄下生成scss.js和bundle.js
node
其中,配置文件的第一行代碼使用了Node的內置模塊path
,而且在它前面加上 __dirname
這個全局變量(也就是第七行代碼)。能夠防止不一樣操做系統之間的文件路徑問題,而且可使相對路徑按照預期工做。 即便你的index.js內容爲空,bundle.js裏面也有一些基本的打包代碼。webpack
//第一種方法,使用當前目錄的node_modules裏面的webpack
./node_modules/.bin/webpack
//第二種方法使用npm腳本
//首先在你的package.json裏面添加下列代碼
{
...
"scripts": {
"build": "webpack"
},
...
}
//而後,使用下列代碼便可
npm run bulid
//第三種方法,高版本的npm自帶了npx
npx webpack //npx會自動查找當前依賴包中的可執行文件,若是找不到,就會去 PATH 裏找。若是依然找不到,就會幫你安裝!
複製代碼
因此說呢,我選擇了第三種使用方法。git
ES6或其餘版本js轉換成通用js代碼,毫無疑問應該使用babel
,不過在webpack
的世界裏面統一使用loader
,因此咱們google webpack babel-loader
。 loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。github
babel-loader
不一樣版本的安裝腳本、配置文件是不一樣的…… web
webpack 3.x babel-loader 7.x | babel 6.x
的去這個
連接,
webpack 3.x | babel-loader 8.x | babel 7.x
的去
當前的這連接連接。 好吧,我用上一版本的吧。 因此個人安裝腳本是
npm install --save-dev babel-loader babel-core babel-preset-env webpack
複製代碼
配置文件是
//依然屬於webpack.config.js配置的一部分,
module: {
//這是關於模塊的配置
rules: [
//模塊規則(配置 loader、解析器等選項)
{
test: /\.js$/, //使用正則判斷後綴是js的文件
exclude: /(node_modules|bower_components)/,
//除了這兩目錄下的node_modules|bower_components
use: {
loader: 'babel-loader', //用這個loader處理.js的文件
options: {
presets: ['env'] //選項,還記得單獨使用babel的時候創建的那個.babelrc嘛,就是那個做用。
}
}
}
]
}
複製代碼
藉此能夠獲得loader
的兩個做用:
./src/js/
有module-1.js、module-2.js、app.js
三個文件,都是新的語法,用的模塊化寫法,有的瀏覽器不支持,因此須要轉化。//module-1.js代碼
function fn(){
console.log(1)
}
export default fn
//module-2.js
function fn(){
console.log(2)
}
export default fn
//app.js
import x from './module-1.js'
import y from './module-2.js'
x()
y()
複製代碼
最終效果,打開的個人預覽連接,使用ctrl+shift+J
,會看到打印出1和2
若是使用了預編譯的scss語言,要把scss文件變成css並加入到html裏面,思路同上,google webpack scss
獲得以下代碼
npm install sass-loader node-sass webpack --save-dev
複製代碼
模塊配置文件
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
複製代碼
這個官方的就比較給力了,很清楚地用法
./src/csa/main.scss
編譯成main.css不過坑爹依舊☺……用的時候報錯嘍~
第一次就說缺style-loader,好吧……自覺點把另外一個一塊兒安裝了把。
npm i --save-dev css-loader style-loader
複製代碼
因此,打開個人預覽連接,會看到個人預覽的背景是灰色的。
const path = require('path');
module.exports = {
entry: './src/js/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/js/')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
},
{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}
]
}
};
複製代碼
因此藉助webpack強大的模塊化,經過其構建的依賴關係圖(dependency graph)把js、scss都搞到了bundle.js裏面,真是牛~
原本搞了一個html-loader,優化html,把空格、註釋都給壓縮掉,提升性能,但是實際使用中也沒有報錯,也沒啥效果,比較尷尬……本身埋個坑後面補一補。
目前呢,前面的loader用的都很爽。在src目錄下修改完了代碼,一個npx webpack,刷新就能夠看到效果了,體驗很棒。 可是今天坐在電腦前面,回想代碼,之前在前端工程話的道路上,scss、js、html都是被監視着(wacth),開四個命令行窗口,只要src下一有風吹草動,就會把修改後的代碼更新過去。
scss、js
了,可我若是修改了src/index.html,dist/也沒法獲知個人修改啊Copy Webpack Plugin
哎呀,是個plugin
,終於webpack的四大基本概念都到齊了,前面搞了entry output loder
,今天用一下plugin
。
loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。 基本安裝
npm i -D copy-webpack-plugin
複製代碼
Copy Webpack Plugin配置文件(plugin的和loader的配置文件可不是一個套路。loader是在module.rules數組的每個對象裏面(即rules數組的每個value),而plugin是在module的plugins數組裏面)
//依然在webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const config = {
plugins: [
new CopyWebpackPlugin([ ...patterns ], options)
]
}
複製代碼
Copy Webpack Plugin的github給的代碼,一開始把我搞蒙了,和webpack官網的代碼不大同樣啊。後來才發現原來用了module.exports = config;
在個人小demo裏使用的是
plugins: [
new CopyWebpackPlugin([ {
//原來一個plugin就是一個對象啊,使用的時候實例化對象便可
from: 'src/index.html', //從src/index.html目錄下複製
to: '../index.html', //到dist/index.html
toType: 'file' //複製類型是文件
}], { copyUnmodified: true }) //把未修改的部分也複製過去
]
複製代碼
這個插件能夠實現不少功能,具體的細節看這裏
上面代碼爲何這麼寫呢to: '../index.html',
,試了好幾遍發現沒有報錯,就是沒有結果,最後搞明白了是路徑的問題…… 還記得 四大基本概念的output
裏面的path嗎,回頭看一開始的path
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/js/')
},
複製代碼
項目的path是dist/js
下,因此應該複製到上一級目錄下../
也就是dist/
目錄下了。
動態效果能夠看下圖
上述代碼有個小問題使用了display: flex
把ul>li
變成了橫排,可是這玩意有兼容性。當初個人一篇文章惟一的一個評論就是這麼說個人……
檢查兼容性(雖然這是嚴謹要求,我仍是老忘),能夠去caniuse 看一下,(@ο@) 哇~IE沒有綠的哎,支持太差了。( ⊙ o ⊙ )!萬一之後我項目搞大了,IE的用戶、老安卓的用戶想看我項目咋辦呢,只能加一下前綴優化一下啦。 有個挺牛的在線的autoprefixer,也能夠去在線轉換。 既然使用了webpack就Google webpack autoprefixer
,遺憾的發現autoprefixer
官方推薦使用postcss-loader
先吐槽一下,這貨的文檔也是稀爛……
npm i -D postcss-loader
複製代碼
module.exports = {
parser: 'sugarss', // 鉿????解析器是sugarss???
plugins: {
'postcss-import': {},
'postcss-cssnext': {},
'cssnano': {}
}
}
複製代碼
在webpack.config.js的添加時還要注意下面的幾點
After setting up your postcss.config.js, add postcss-loader to your webpack.config.js. You can use it standalone or in conjunction with css-loader (recommended). Use it after css-loader and style-loader, but before other preprocessor loaders like e.g sass|less|stylus-loader, if you use any.
這段文檔的要點就是讓你注意postcss-loader
應該在css-loader style-loader
以後,可是必定要在其餘的預處理器preprocessor loaders
以前,例如 sass|less|stylus-loader
。
//依然是webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader'
]
}
]
}
}
複製代碼
本項目用的是.src/css/main.scss
,只能嘗試着將上述代碼加到相應的位置
rules: [
...
{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", options: { importLoaders: 1 }// translates CSS into CommonJS
}, {
loader: "postcss-loader"
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
},
...
]
複製代碼
下面的幾點可都是官網文檔沒寫的,只能本身踩一踩的坑……
npx webpack
,連續報錯,不過是缺必備的module的錯誤,也就是缺postcss.config.js裏面的postcss-import postcss-cssnext cssnano sugarss
。 沒辦法,先npm i -D 上面的四個模塊名字
,依然報錯,此次是語法錯誤
(⊙v⊙)嗯???它說我沒必要要的大括號???我這標準的scss語法啊,又不是sass的語法(它省略了大括號和分號),先Google一波這個錯誤。 終於在在postcss的issue裏面發現了蛛絲馬跡,問題果真出在那個令我疑惑的postcss.config.js
裏面postcss-loader
哪來的勇氣肯定你們都是用的.sss
後綴的sugarss語法呢,還敢直接在文檔的醒目位置推薦稀爛的postcss.config.js
,O__O "…註釋掉parser: 'sugarss',
這句代碼,可使用默認的解析器去解析了,正常運行了。 不過查看代碼,發現好像轉換後的css有點小醜
仔細觀察命令行,發現有線索,一個警告
警告信息提示我說:postcss-cssnext發現有個冗餘的autoprefixer
插件在個人postcss插件裏面,這個可能有不良影響,我應該移除它,由於它已經包括在了postcss-cssnext裏面。
webpack的警告說的很明白,postcss-cssnext是無辜的,並且我肯定按照官網代碼走的,沒有安裝autoprefixer
插件,錯誤必然在剩下的兩個插件裏面了。
//修改後的postcss.config.js只剩下這些了
module.exports = {
plugins: {
'postcss-import': {}, //1.它錯了?
'postcss-cssnext': {}, //webpack告訴我它是清白的
'cssnano': {} //2.它錯了?
}
}
複製代碼
我選擇了排除法:
'postcss-import': {},
,發現沒法轉換後的css代碼不對,說明它是無辜的。'cssnano': {}
,終於完美了,並且代碼很優美。
本着打破砂鍋問到底的精神,我搜了一下cssnano
,在其官網看到了真實的錯誤緣由,webpack很明智啊,誠不欺我,果真冗餘插件了。
cssnano裏面有autoprefixer
致使了冗餘。
webpack 把全部的資源都當成了一個模塊, CSS、JS 文件 都是資源, 均可以打包到一個 bundle.js 文件中. 可是有時候須要把樣式 單獨的打包成一個文件須要抽離出css文件到單獨的css/
下。
使用extract-text-webpack-plugin插件能夠作到。
npm install extract-text-webpack-plugin --save-dev
複製代碼
const ExtractTextPlugin = require("extract-text-webpack-plugin"); //插件的套路。都要require進來
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader", //失敗了就用它解析
use: "css-loader" //是css文件,就用這個處理
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
}
複製代碼
我若是使用的是scss,就很尷尬了
最開始由一個錯誤引發
Google一下,解決掉error,fallbak裏面使用了style-loader,use裏面不該該使用了,那麼問題又來了
詳見代碼註釋部分
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//若是在use裏面寫上style-loader,就報錯window未被定義,但是不寫的話,個人bundle.js裏面就沒法把css放到style標籤裏面,只能手動把分離的css加到index.html,很無語。
use: [{
loader: "css-loader", options: { importLoaders: 1 }// translates CSS into CommonJS
}, {
loader: "postcss-loader"
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
})
}
複製代碼
css/
下,很尷尬,代碼未提交,還在摸索中。問題大約知道應該出如今下面這個函數裏面
new ExtractTextPlugin({
filename: (getPath) => {
return getPath('../main.css').replace('../js', '../css'); // 本意是生成在dist/css/main.css,結果只是在dist/main.css目錄下,沒有css/
},
allChunks: true
})
複製代碼
全部的代碼都在個人demo裏面。
算……是……搞定了webpack的基本使用了……吧,最簡單的符合我目前技術棧的各類loader,plugin都會安裝了。 固然,還有無數的webpack的loader、plugin在前方等着我去探索……各類稀奇古怪的配置文件……痛並快樂着☺
五花八門的配置文件挺讓我糟心的……幸好有了node爸爸幫我啊,webpack爸爸雖然也是比較嚴厲的,可是省了你用四個命令行窗口的啊,仍是很感人的啊。
工具這個東西嘛
沒有什麼bug不是一遍webpack解決不了額,若是有的話,那就來三遍webpaack。總有一天讓webpack叫你爸爸!!!
如今的吐槽大概是沒有經歷過之前更蛋疼的日子吧,幸虧有了新的後起之秀---parcel,它的官網老厲害了,智能提示我用了中文,真是貼心。
回顧一下webpack
的首頁
在對比一下parcel
的首頁
二者的目的是同樣的,不過parcel不須要插件,並且速度快。
沒有配置,最好以html或者js爲入口,直接npm init -y , parcel index.html
,能夠實現index.js。
它會自動幫你打包到dist目錄下的一個js文件裏面,並複製index.html過去,而這一切只須要上面的一行代碼。
parcel index.html
的目錄結構而我當時搞webpack的時候的快速開始至少須要安裝webpack、webpack.config.js、修改配置內容、安裝插件才能實現上述的功能。
當我在parcel-demo
目錄下使用parcel index.html
的時候,它自動發現我引入了index.js。
<body>
<script src="./index.js"></script>
</body>
複製代碼
dist/parcel-demo.js
,我在webpack的時候須要babel-loader還幫我自動下載了node-sass
其餘的特色都在官網去發掘吧~但願往後parcel
快速崛起吧
而如今我仍是要用webpack
的……