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