摘要:使用等預(yù)處理器編寫可以將你項(xiàng)目中的所有文件,處理成瀏覽器能識別的文件。測試打包基本的配置就完成了。修改處理文件執(zhí)行順序是從右到左修改一下入口文件中的樣式引入打包測試完美通過。這時可以使用提供的配置來使引入文件的時候變得更加方便簡單。
本文正文鏈接
最近公司弄了個有150+頁面的項(xiàng)目,心想,終于有機(jī)會可以去學(xué)習(xí)webpack了,以前想學(xué)卻沒有實(shí)際項(xiàng)目去引導(dǎo)逼迫去學(xué),現(xiàn)在終于領(lǐng)略到了webpack的強(qiáng)大了。
什么是webpack在前端的項(xiàng)目開發(fā)中,總有大量的頁面和樣式需要處理,而維護(hù)這些文件也成了頭疼的問題。
為了簡化開發(fā),于是就有很多好的開發(fā)方式,如:
模塊化開發(fā)。每個功能模塊都分開成一個個獨(dú)立的組件,需要的時候再引入。
scss等預(yù)處理器。
使用pug, jade 更快編寫HTML。
...
這些方式確實(shí)可以大大提高開發(fā)效率,但是每種方式都有自己的打包方式,還有兼容性處理,如果純手動處理,必然會增加工作量。
但是,現(xiàn)在有了webpack,上述問題基本解決了,一個webpack就可以處理各種繁瑣的過程,給你一個清爽,快速的開發(fā)環(huán)境。
</>復(fù)制代碼
WebPack可以看做是模塊打包機(jī):它做的事情是,分析你的項(xiàng)目結(jié)構(gòu),找到JavaScript模塊以及其它的一些瀏覽器不能直接運(yùn)行的拓展語言(Scss,TypeScript等),并將其轉(zhuǎn)換和打包為合適的格式供瀏覽器使用。
簡單的來說,在項(xiàng)目開發(fā)中,
你可以使用js,es6/7,甚至ts開發(fā)。
es6/es7, .ts => .js
使用stylus, scss, less 等預(yù)處理器編寫css
.scss/.less => .css
webpack可以將你項(xiàng)目中的所有文件,處理成瀏覽器能識別的文件。
開始使用webpack先新建一個練手用的空文件夾 $ mkdir webpack-demo ,并進(jìn)入該文件夾。
新建 package.json.
</>復(fù)制代碼
$ npm init
安裝webpack及其基本插件。
</>復(fù)制代碼
$ npm i -D webpack extract-text-webpack-plugin html-webpack-plugin css-loader file-loader style-loader url-loader
其中:
extract-text-webpack-plugin : 該插件主要為了抽離css樣式,可以將css從打包的js中抽離出來。以link方式引入樣式。
html-webpack-plugin : 該插件主要是用于生成html文件,并可以根據(jù)入口文件來引入相應(yīng)的文件。
css-loader : 解析css文件中的 import 和 require ,并處理他們。
style-loader : 將css樣式通過 style 標(biāo)簽注入到html文件中。
file-loader : 指明webpack將所引入的對象,并返回一個公網(wǎng)能訪問的url地址。
url-loader : 將文件轉(zhuǎn)換成 base64編碼。
配置webpack。
新建一個配置文件: $ touch webpack.config.js
</>復(fù)制代碼
var webpack = require("webpack");
var path = require("path");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var webpackConfig = {
// 設(shè)置入口文件。
entry: "./src/js/index.js",
output: {
// 設(shè)置輸出文件夾
path: path.join(__dirname, "dist"),
// 設(shè)置公用文件夾路徑
publicPath: "/",
// 設(shè)置輸出的js文件的名字規(guī)則。
// [name] 為chunk中的名稱
// [hash] 為webpack生成的哈希值
filename: "js/[name].[hash].bundle.js"
},
module: {
rules: [{
// 處理css文件
test: /.css$/,
loader: "style-loader!css-loader"
}, {
// 處理html文件,并處理img 中 src 和 data-src 的引入路徑
test: /.html$/,
loader: "html-loader?attrs=img:src img:data-src"
}, {
// 處理字體文件
test: /.(woff|woff2|ttf|eot|svg)(?v=[0-9].[0-9].[0-9])?$/,
loader: "file-loader?name=./fonts/[name].[ext]"
}, {
// 處理圖片,并將8k以下的圖片轉(zhuǎn)為base64編碼
test: /.(png|jpg|gif)$/,
loader: "url-loader?limit=8192&name=./img/[hash].[ext]"
}]
},
plugins: [
// 公共js提取
new webpack.optimize.CommonsChunkPlugin({
name: "vendors", // 將公共模塊提取,生成名為`vendors`的chunk
// minChunks: 3 // 提取至少3個模塊共有的部分
}),
// 提取公共css樣式
new ExtractTextPlugin("./css/[name].css"),
// 處理html文件。
new HtmlWebpackPlugin({
filename: "./view/index.html", //生成的html存放路徑,相對于path
template: "./src/view/index.html", //html模板路徑
inject: "body", //js插入的位置,true/"head"/"body"/false
hash: true, //為靜態(tài)資源生成hash值
// chunks: ["vendors", allDirs[i] + "/" + matches[1]], //需要引入的chunk,不配置就會引入所有頁面的資源
minify: { //壓縮HTML文件
removeComments: true, //移除HTML中的注釋
collapseWhitespace: false //刪除空白符與換行符
}
})
],
// 設(shè)置開發(fā)服務(wù)器
devServer: {
contentBase: path.join(__dirname, "dist/"),
host: "localhost",
port: 9090,
inline: true
}
}
module.exports = webpackConfig
測試配置文件:
先設(shè)置開發(fā)文件夾目錄:
</>復(fù)制代碼
- webpack-demo
+ node_modules
- src
+ js // 存放js文件
+ css // 存放css樣式
+ view // 存放模板文件
webpack.config.js
package.json
新建一個 html 文件: $ touch ./src/view/index.html。
</>復(fù)制代碼
<span class="hljs-attr">Hello</span> <span class="hljs-string">World</span>
Hello World
This is from webpack-demo
新建css文件: $ touch ./src/css/index.css。
</>復(fù)制代碼
h2{
color: red;
opacity: 0.5;
transform: rotateZ(-10deg);
}
p{
color: green;
}
新建js文件: $ touch ./src/js/index.js。
</>復(fù)制代碼
// 引入css文件。
require("../css/index.css")
console.log("hello world");
測試打包: $ webpack
OK!基本的配置就完成了。
我們可以看到,在項(xiàng)目中多了一個dist文件夾,里面存放的就是剛剛打包好的文件。打開index.html(需要在服務(wù)器中打開,并且服務(wù)器根目錄為dist)可以看到,生成的html文件,征程顯示我們寫的內(nèi)容,css樣式則直接寫入了style標(biāo)簽當(dāng)中,而且自動引入了兩個js文件,其中,vendors是帶有公共部分的js文件,index則是我們一開始寫的js邏輯文件。
既然都用到了webpack自動打包了,那也順便使用webpack去處理scss文件(個人愛好是scss,less的處理同理),順便也處理完css中的其他兼容性問題和瀏覽器前綴問題吧(程序員的思維就是,懶)。
現(xiàn)在css中需要處理的有:
瀏覽器前綴和大部分兼容性問題: autoprefixer
flex 的兼容性問題: postcss-flexibility
opacity 兼容IE: postcss-opacity
顏色兼容性問題: postcss-color-rgba-fallback
scss文件處理: sass-loader 同時需要依賴 node-sass
壓縮css文件: cssnano
安裝上書postcss-loader的插件: $ npm i -D autoprefixer postcss-flexibility postcss-opacity postcss-color-rgba-fallback sass-loader node-sass
現(xiàn)在在webpack中處理css的問題,基本都是通過一個 postcss-loader 去完成所有的處理問題。
先新建一個文件夾,用于存放所有的scss文件: $ mkdir ./src/scss
再新建一個index.scss, $ touch ./src/scss/index.scss
</>復(fù)制代碼
body{
background: black;
color: white;
h2{
transform: translateX(10px) rotateZ(-10deg);
color: red;
opacity: 0.5;
}
}
將postcss的加載器中需要的多帶帶提取出來放在一個配置文件中: $ touch postcss.config.js
</>復(fù)制代碼
module.exports = {
plugins: [
// minify css
require("cssnano")({
preset: "default"
}),
// 處理css前綴
require("autoprefixer")({
browserslist: [
"> 1%",
"last 2 versions",
"Edge",
"ie >= 9"
]
}),
// 處理flex瀏覽器兼容性
require("postcss-flexibility"),
// 處理css中rgba顏色代碼
require("postcss-color-rgba-fallback"),
// 處理css中opacity的IE兼容性。
require("postcss-opacity")
]
}
修改 webpack.config.js:
</>復(fù)制代碼
var webpackConfig = {
...
module: {
rules: [{
// 處理css文件
test: /.(scss|sass|css)$/,
// loader: "css-loader?importLoaders=1!postcss-loader!sass-loader",
// loader執(zhí)行順序是從右到左:sass-loader -> postcss-loader -> css-loader
use: [
"style-loader",
{
loader: "css-loader",
options: {
// // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
importLoaders: 2
}
},
"postcss-loader",
"sass-loader"
]
},
...
]
}
...
}
module.exports = webpackConfig
修改一下入口文件中的樣式引入: $ vim ./src/js/index.js
</>復(fù)制代碼
require("../scss/index.scss")
console.log("hello world");
打包測試:
完美通過。
處理pug/jade文件項(xiàng)目有很多的頁面,而且頁面之間也有很多相同的頁面,之前寫慣了vue的組件,所以注冊我們也引入了pug作為前端模板引擎。 pug 的前身就是 jade ,所以語法什么都得基本都是一致的。具體的看 官網(wǎng) 。
和處理css的一樣,先要安裝加載器。 $ npm i -D pug pug-loader
新建一個簡單的頁面: $ touch ./src/view/index.pug
</>復(fù)制代碼
html
title Test.html
body
h2 Welcome to pug.
p This is from index.pug
修改一下配置文件中的html模板入口:
</>復(fù)制代碼
var webpackConfig = {
...
plugins: [
// 公共js提取
new webpack.optimize.CommonsChunkPlugin({
name: "vendors", // 將公共模塊提取,生成名為`vendors`的chunk
}),
// 提取公共css樣式
new ExtractTextPlugin("./css/[name].css"),
// 處理html文件。
new HtmlWebpackPlugin({
filename: "./view/index.html", //生成的html存放路徑,相對于path
template: "./src/view/index.pug", //html模板路徑
inject: "body", //js插入的位置,true/"head"/"body"/false
hash: true, //為靜態(tài)資源生成hash值
chunks: ["vendors", "index"], //需要引入的chunk,不配置就會引入所有頁面的資源
minify: { //壓縮HTML文件
removeComments: true, //移除HTML中的注釋
collapseWhitespace: false //刪除空白符與換行符
}
})
],
...
}
module.exports = webpackConfig
重新編譯打包:
在項(xiàng)目開發(fā)中,難免會遇到使用 es6 ,甚至 es7 去編寫js。但是大部分瀏覽器卻不支持這些語法,這時候,就需要 babel-loader 來處理js,并將其轉(zhuǎn)換為瀏覽器能識別的 es5 語法。
還是要安裝依賴: $ npm i -D babel-loader babel-core babel-preset-es2015
如果用上了es7 的語法,就要根據(jù)不同階段語法提案的轉(zhuǎn)碼規(guī)則(共有4個階段),選裝一個:
</>復(fù)制代碼
$ npm i -D babel-preset-stage-0
$ npm i -D babel-preset-stage-1
$ npm i -D babel-preset-stage-2
$ npm i -D babel-preset-stage-3
新建一個 .babelrc babel配置文件: $ touch .babelrc
</>復(fù)制代碼
{
"presets": ["es2015"],
"plugins": []
}
修改 webpack 配置文件:
</>復(fù)制代碼
var webpackConfig = {
...
module: {
rules: [{
test: /.js$/,
// 不編譯 node_modules 下的文件
exclude: /node_modules/,
loader: "babel-loader"
}]
}
...
}
module.exports = webpackConfig
在 index.js 中寫個 es6 的語法:
</>復(fù)制代碼
require("../scss/index.scss")
console.log("hello world");
((message) => {
console.log(message);
})("message from es6")
let step = 2;
var add = number => number*=step
console.log(add(2));
來,打包看看:
完美。
項(xiàng)目有多個頁面,每個頁面都對應(yīng)著一個js入口和一個頁面,但是,入口 entry 和 html-webpack-plugin 每次只能配置一個具體的入口文件,如果每增加一個頁面就要去配置,那么這無形之中增加了工作量,因此,我們需要一個通用的入口文件。
既然在node中可以訪問文件夾并讀取其中的文件名,那么我們可以使用node來去循環(huán)讀取文件夾下的js文件,并自動添加至入口配置中:
新建一個config 文件夾,以存放webpack可變的配置,方便以后修改: $ mkdir config
因?yàn)楸闅v入口文件都是一樣的操作流程,所以先寫一個工具包:$ touch config/utils.js
</>復(fù)制代碼
var fs = require("fs");
// 遞歸遍歷文件夾,獲取入口文件
function getAllFiles(dirRoot, type){
var filterReg = new RegExp("."+type+"$");
function getAllFileFromDir(root) {
var res = [], files = fs.readdirSync(root)
files.forEach((file) => {
var pathname = root+"/"+file,
state = fs.lstatSync(pathname)
if (!state.isDirectory()) {
// 過濾相對應(yīng)的文件
filterReg.test(pathname) && res.push(pathname)
// res.push(pathname.replace(dir_root+"/", ""))
}else{
res = res.concat(getAllFileFromDir(pathname))
}
})
return res
}
return getAllFileFromDir(dirRoot)
}
function getEntry(files, replaces){
var entry = {}
for (var i = 0; i < files.length; i++) {
var filename = files[i]
replaces.map((replace) => {
filename = filename.replace(replace, "")
})
entry[filename] = files[i]
}
return entry
}
module.exports = {
getAllFiles,
getEntry
}
再新建一個 js 入口文件配置: $ touch config/webpack.entry.js
</>復(fù)制代碼
var path = require("path");
var utils = require("./utils.js")
var dir_root = path.resolve(__dirname, "../src/js");
// console.log(getAllFiles(dir_root));
var allFiles = utils.getAllFiles(dir_root, "js")
var entry = utils.getEntry(allFiles, ["js", dir_root+"/"])
console.log(entry);
module.exports = entry
同樣的,頁面入口文件也添加一個: $ touch config/webpack.plugins.js
</>復(fù)制代碼
var webpack = require("webpack")
var path = require("path");
var utils = require("./utils.js")
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var entry = require("./webpack.entry.js")
var plugins = [
// 公共js提取
new webpack.optimize.CommonsChunkPlugin({
name: "vendors", // 將公共模塊提取,生成名為`vendors`的chunk
minChunks: 3 // 提取至少3個模塊共有的部分
}),
// 提取公共css樣式
new ExtractTextPlugin("./css/[name].css"),
]
let dir_root = path.resolve(__dirname, "../src/view");
var pugFiles = utils.getAllFiles(dir_root, "pug")
pugFiles = utils.getEntry(pugFiles, [".pug", dir_root+"/"])
for (var key in pugFiles) {
if (pugFiles.hasOwnProperty(key)) {
let opt = {
filename: "./view/"+ key +".html",
template: pugFiles[key],
hash: true,
minify: { //壓縮HTML文件
removeComments: true, //移除HTML中的注釋
collapseWhitespace: false //刪除空白符與換行符
}
}
if (entry.hasOwnProperty(key)) {
opt["chunks"] = ["vendors", key]
opt["inject"]= "body"
}
console.log(opt);
plugins.push(new HtmlWebpackPlugin(opt))
}
}
module.exports = plugins
再次修改webpack的配置:
</>復(fù)制代碼
var entry = require("./config/webpack.entry.js")
var plugins = require("./config/webpack.plugins.js")
var webpackConfig = {
entry,
plugins,
...
}
module.exports = webpackConfig
可以看到,dist文件夾下,多了幾個html文件和js文件。
提取css到外部link,而非style標(biāo)簽
這個解決辦法比較簡單,只需要用 extract-text-webpack-plugin 插件將css提取出來即可:
</>復(fù)制代碼
{
test: /.(scss|sass|css)$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: "css-loader",
options: {
// // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
importLoaders: 2
}
},
"postcss-loader",
"sass-loader"
]
})
}
再次打包的結(jié)果:
列出dis文件夾的目錄樹可以發(fā)現(xiàn),多了一個css的文件夾。打開頁面可以發(fā)現(xiàn),頁面中的style標(biāo)簽已經(jīng)被link替代了。
每次打包舊的文件依舊存在
每次執(zhí)行webpack打包(當(dāng)然在實(shí)際開發(fā)中應(yīng)該使用熱更新服務(wù)器,不需要頻繁打包)都會產(chǎn)生一堆新的js文件。
解決辦法:
一是將打包的js文件的hash值去掉,這樣就會新的打包js文件,將舊的覆蓋。
二是使用 clean-webpack-plugin
</>復(fù)制代碼
var CleanWebpackPlugin = require("clean-webpack-plugin");
var plugins = [
// 每次打包前都清空dist文件
new CleanWebpackPlugin(["dist"], {
root: path.resolve(__dirname, "../")
}),
// 公共js提取
new webpack.optimize.CommonsChunkPlugin({
name: "vendors", // 將公共模塊提取,生成名為`vendors`的chunk
// minChunks: 3 // 提取至少3個模塊共有的部分
}),
// 提取公共css樣式
new ExtractTextPlugin("./css/[name].css"),
]
批量新建文件
因?yàn)槊總€頁面基本都有3個文件:page.pug, page.js, page.scss,如果每次新加一個頁面都要手動新建3個文件的話,效率太低下,能用命令行解決的,當(dāng)然要用命令行解決啦。
先寫個小腳本 newpage.sh:
</>復(fù)制代碼
#!/bin/sh
if [[ $1 ]]; then
filename=$1
touch ./src/js/$filename.js
touch ./src/view/$filename.pug
touch ./src/scss/$filename.scss
fi
使用方式就是: $ ./newpage.sh filename,要運(yùn)行該腳本,就需要先將腳本設(shè)置為可執(zhí)行: $ sudo chmod +x ./newpage.sh。
還可以將它寫進(jìn) npm 的 package.json 的命令中,則命令可以變?yōu)椋?b>npm run new -- filename
</>復(fù)制代碼
{
"script": {
"new": "./newpage.sh"
}
}
定義路徑常量
在編寫js時,因?yàn)橛锌赡躩s文件是在很多級的目錄當(dāng)中,如果每次都使用 .. 來定位上一層目錄的話,那么這個定位就會十分繁瑣。這時可以使用 webpack 提供的 resolve.alias 配置來使引入文件的時候變得更加方便簡單。
</>復(fù)制代碼
resolve: {
alias: {
scss: path.resolve(__dirname, "src/scss"),
js: path.resolve(__dirname, "src/js"),
view: path.resolve(__dirname, "src/view"),
assets: path.resolve(__dirname, "src/assets")
}
}
這樣,在 other.js 中,就可以直接使用 require("scss/about.scss") 而不需要寫繁瑣的 require("../../scss/about.scss")。這樣就方便多了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84895.html
摘要:一組鏈?zhǔn)降膶凑障群箜樞蜻M(jìn)行編譯。在最后一個,返回所預(yù)期的。運(yùn)行在中,并且能夠執(zhí)行任何可能的操作。用于對傳遞配置。分開的每個部分都相對于當(dāng)前目錄解析。 webpack自稱能夠打包任何文件,這句話咋聽一下好像在吹牛逼,因?yàn)閣ebpack本身只能理解JavaScript。但是由于webpack中有l(wèi)oader的存在,可以將所有類型的文件轉(zhuǎn)換為webpack能夠處理的有效模塊,然后利用we...
摘要:然而,這些模板并不限制你自己對于使用的架構(gòu)組織和選擇類庫。目前可用的模板包括全功能的,包括熱加載,靜態(tài)檢測,單元測試一個簡易的,以便于快速開始。 最近, 尤大在和人對噴的時候,悄然放出了一個大招,于是為了追趕他的步伐,趕緊試驗(yàn)了下,并且把原文給大家翻譯下。 原文地址:Announcing vue-cli 譯文源地址: Vuejs自己的構(gòu)建工具 先上原文翻譯: 最近有很多大量關(guān)于Reac...
摘要:五六月份推薦集合查看最新的請點(diǎn)擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請點(diǎn)擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
閱讀 2121·2021-11-23 10:06
閱讀 3483·2021-11-11 16:54
閱讀 3349·2019-08-29 17:31
閱讀 3573·2019-08-29 17:05
閱讀 2173·2019-08-26 13:36
閱讀 2165·2019-08-26 12:17
閱讀 530·2019-08-26 12:12
閱讀 1679·2019-08-26 10:19