webpack構(gòu)建vue項(xiàng)目的詳細(xì)教程(配置篇)
最近公司要求用vue重構(gòu)項(xiàng)目,還涉及到模塊化開發(fā),于是乎,我專門花了幾天的時間研究了一下webpack這個目前來看比較熱門的模塊加載兼打包工具,發(fā)現(xiàn)上手并不是很容易,現(xiàn)將總結(jié)的一些有關(guān)配置的心得分享出來,歡迎大神來拍磚。。。
一、新建一個項(xiàng)目目錄,cd /d 定位進(jìn)去,然后輸入npm init,會提示你填寫一些項(xiàng)目的信息,一直回車默認(rèn)就好了,或者直接執(zhí)行npm init -y 直接跳過,這樣就在項(xiàng)目目錄下生成了一個package.json文件。
二、接下來就是通過npm安裝項(xiàng)目依賴項(xiàng),命令行輸入:npm install babel-loader babel-core babel-plugin-transform-runtime babel-preset-es2015 babel-preset-stage-0 babel-runtime vue-loader vue-html-loader vue-hot-reload-api css-loader style-loader webpack webpack-dev-server --save-dev ,繼續(xù)輸入npm install vue@^1.0.26 --save 。
這里注意的幾個點(diǎn)如下:
1.需要安裝的依賴項(xiàng)視具體的項(xiàng)目需求來定,我只是安了幾個必需的,后期會再加;
2.輸入之后如果一直報錯或者光標(biāo)一直在轉(zhuǎn)動,要么是npm版本太低(需要3+),要么將npm改成cnpm,如果沒有安裝淘寶NPM鏡像,可以先輸入npm install -g cnpm --registry=https://registry.npm.taobao.org,接著輸入cnpm -v查看是否安裝完成,然后就可以使用cnpm來代替npm;
3.可以先修改package.json文件中的devDependencies和dependencies,然后再輸入npm install進(jìn)行一次性安裝(偷懶的做法,嘿嘿);
4.dependencies中的vue默認(rèn)安裝2+,如果dependencies中的vue選擇^1.0.26,那么devDependencies中對應(yīng)的vue-loader最好選擇^7.3.0,vue-hot-reload-api最好選擇^1.2.0,否則就會報錯;
5.dependencies中的vue-router默認(rèn)安裝2+,無法識別router.map()這個方法,如果想要用回這個方法,最好選擇^0.7.13;
6.有時安裝一個依賴項(xiàng),會提示還需要一并安裝別的依賴項(xiàng),例如:如果要安裝bootstrap-loader,會提示要求安裝node-sass sass-loader resolve-url-loader;要安裝less-loader,會提示要求安裝less;
完成這一步之后,會在項(xiàng)目目錄下生成一個名node_modules的文件,對應(yīng)的package.json文件中的內(nèi)容變動如下(我額外添加了幾個依賴項(xiàng)):
"devDependencies": {
"autoprefixer-loader": "^3.2.0",
"babel-core": "^6.18.2",
"babel-loader": "^6.2.7",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-0": "^6.16.0",
"babel-runtime": "^6.18.0",
"css-loader": "^0.25.0",
"debug": "^2.2.0",
"express": "^4.14.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"html-webpack-plugin": "^2.24.1",
"jquery": "^3.1.1",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
"vue-hot-reload-api": "^1.2.0",
"vue-html-loader": "^1.2.3",
"vue-loader": "^7.3.0",
"webpack": "^1.13.3",
"webpack-dev-middleware": "^1.8.4",
"webpack-dev-server": "^1.16.2",
"webpack-hot-middleware": "^2.13.1"
},
"dependencies": {
"vue": "^1.0.26",
"vue-router": "^0.7.13"
}
三、在項(xiàng)目目錄下新建一個名為src的目錄,里面用于存放入口文件(index.js)、項(xiàng)目源文件(html,css,js,img之類的)、組件(.vue后綴),我的src目錄結(jié)構(gòu)大致如下:
src -entry -index.js -pages -components -css -img -js -index.html -public
當(dāng)然,有輸入目錄,就有輸出目錄,即在項(xiàng)目目錄下新建一個output目錄,用于放置生產(chǎn)出來的各種資源文件。
四、在項(xiàng)目目錄下新建一個名為build目錄,里面用于存放各種配置文件,涉及到基礎(chǔ)配置、開發(fā)和生產(chǎn)環(huán)境、靜態(tài)服務(wù)器以及熱加載,詳細(xì)的內(nèi)容請看下面的代碼:
1.webpack.config.js(基礎(chǔ)配置文件)
// 引入依賴模塊
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// 入口文件,路徑相對于本文件所在的位置,可以寫成字符串、數(shù)組、對象
entry: {
// path.resolve([from ...], to) 將to參數(shù)解析為絕對路徑
index:path.resolve(__dirname, '../src/entry/index.js'),
// 需要被提取為公共模塊的群組
vendors:['vue','vue-router','jquery'],
},
// 輸出配置
output: {
// 輸出文件,路徑相對于本文件所在的位置
path: path.resolve(__dirname, '../output/static/js/'),
// 設(shè)置publicPath這個屬性會出現(xiàn)很多問題:
// 1.可以看成輸出文件的另一種路徑,差別路徑是相對于生成的html文件;
// 2.也可以看成網(wǎng)站運(yùn)行時的訪問路徑;
// 3.該屬性的好處在于當(dāng)你配置了圖片CDN的地址,本地開發(fā)時引用本地的圖片資源,上線打包時就將資源全部指向CDN了,如果沒有確定的發(fā)布地址不建議配置該屬性,特別是在打包圖片時,路徑很容易出現(xiàn)混亂,如果沒有設(shè)置,則默認(rèn)從站點(diǎn)根目錄加載
// publicPath: '../static/js/',
// 基于文件的md5生成Hash名稱的script來防止緩存
filename: '[name].[hash].js',
// 非主入口的文件名,即未被列在entry中,卻又需要被打包出來的文件命名配置
chunkFilename: '[id].[chunkhash].js'
},
// 其他解決方案
resolve: {
// require時省略的擴(kuò)展名,遇到.vue結(jié)尾的也要去加載
extensions: ['','.js', '.vue'],
// 模塊別名地址,方便后續(xù)直接引用別名,無須寫長長的地址,注意如果后續(xù)不能識別該別名,需要先設(shè)置root
alias:{}
},
// 不進(jìn)行打包的模塊
externals:{},
// 模塊加載器
module: {
// loader相當(dāng)于gulp里的task,用來處理在入口文件中require的和其他方式引用進(jìn)來的文件,test是正則表達(dá)式,匹配要處理的文件;loader匹配要使用的loader,"-loader"可以省略;include把要處理的目錄包括進(jìn)來,exclude排除不處理的目錄
loaders: [
// 使用vue-loader 加載 .vue 結(jié)尾的文件
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: /node_modules/
},
// 使用babel 加載 .js 結(jié)尾的文件
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
query:{
presets: ['es2015', 'stage-0'],
plugins: ['transform-runtime']
}
},
// 使用css-loader和style-loader 加載 .css 結(jié)尾的文件
{
test: /\.css$/,
// 將樣式抽取出來為獨(dú)立的文件
loader: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader"),
exclude: /node_modules/
},
// 使用less-loader、css-loader和style-loade 加載 .less 結(jié)尾的文件
{
test: /\.less$/,
// 將樣式抽取出來為獨(dú)立的文件
loader: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader!less-loader"),
exclude: /node_modules/
},
// 加載圖片
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
query: {
// 把較小的圖片轉(zhuǎn)換成base64的字符串內(nèi)嵌在生成的js文件里
limit: 10000,
// 路徑要與當(dāng)前配置文件下的publicPath相結(jié)合
name:'../img/[name].[ext]?[hash:7]'
}
},
// 加載圖標(biāo)
{
test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
loader: 'file-loader',
query: {
// 把較小的圖標(biāo)轉(zhuǎn)換成base64的字符串內(nèi)嵌在生成的js文件里
limit: 10000,
name:'../fonts/[name].[ext]?[hash:7]',
prefix:'font'
}
},
]
},
// 配置插件項(xiàng)
plugins: []
}
2.webpack.dev.config.js(開發(fā)環(huán)境下的配置文件)
// 引入依賴模塊
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
// 引入基本配置
var config = require('./webpack.config.js');
// 必須修改原配置中網(wǎng)站運(yùn)行時的訪問路徑,相當(dāng)于絕對路徑,修改完之后,當(dāng)前配置文件下的很多相對路徑都是相對于這個來設(shè)定;
// 注意:webpack-dev-server會實(shí)時的編譯,但是最后的編譯的文件并沒有輸出到目標(biāo)文件夾,而是保存到了內(nèi)存當(dāng)中
config.output.publicPath = '/';
// 重新配置模塊加載器
config.module= {
// test是正則表達(dá)式,匹配要處理的文件;loader匹配要使用的loader,"-loader"可以省略;include把要處理的目錄包括進(jìn)來,exclude排除不處理的目錄
loaders: [
// 使用vue-loader 加載 .vue 結(jié)尾的文件
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: /node_modules/
},
// 使用babel 加載 .js 結(jié)尾的文件
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
query:{
presets: ['es2015', 'stage-0'],
plugins: ['transform-runtime']
}
},
// 使用css-loader、autoprefixer-loader和style-loader 加載 .css 結(jié)尾的文件
{
test: /\.css$/,
// 將樣式抽取出來為獨(dú)立的文件
loader: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader"),
exclude: /node_modules/
},
// 使用less-loader、autoprefixer-loader、css-loader和style-loade 加載 .less 結(jié)尾的文件
{
test: /\.less$/,
// 將樣式抽取出來為獨(dú)立的文件
loader: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader!less-loader"),
exclude: /node_modules/
},
// 加載圖片
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
query: {
// 把較小的圖片轉(zhuǎn)換成base64的字符串內(nèi)嵌在生成的js文件里
limit: 10000,
// 路徑和生產(chǎn)環(huán)境下的不同,要與修改后的publickPath相結(jié)合
name: 'img/[name].[ext]?[hash:7]'
}
},
// 加載圖標(biāo)
{
test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
loader: 'file-loader',
query: {
limit: 10000,
// 路徑和生產(chǎn)環(huán)境下的不同,要與修改后的publickPath相結(jié)合
name:'fonts/[name].[ext]?[hash:7]',
prefix:'font'
}
},
]
};
// 重新配置插件項(xiàng)
config.plugins = [
// 位于開發(fā)環(huán)境下
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
// 自動生成html插件,如果創(chuàng)建多個HtmlWebpackPlugin的實(shí)例,就會生成多個頁面
new HtmlWebpackPlugin({
// 生成html文件的名字,路徑和生產(chǎn)環(huán)境下的不同,要與修改后的publickPath相結(jié)合,否則開啟服務(wù)器后頁面空白
filename: 'src/pages/index.html',
// 源文件,路徑相對于本文件所在的位置
template: path.resolve(__dirname, '../src/pages/index.html'),
// 需要引入entry里面的哪幾個入口,如果entry里有公共模塊,記住一定要引入
chunks: ['vendors','index'],
// 要把<script>標(biāo)簽插入到頁面哪個標(biāo)簽里(body|true|head|false)
inject: 'body',
// 生成html文件的標(biāo)題
title:''
// hash如果為true,將添加hash到所有包含的腳本和css文件,對于解除cache很有用
// minify用于壓縮html文件,其中的removeComments:true用于移除html中的注釋,collapseWhitespace:true用于刪除空白符與換行符
}),
// 提取css單文件的名字,路徑和生產(chǎn)環(huán)境下的不同,要與修改后的publickPath相結(jié)合
new ExtractTextPlugin("[name].[contenthash].css"),
// 提取入口文件里面的公共模塊
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
filename: 'vendors.js',
}),
// 為組件分配ID,通過這個插件webpack可以分析和優(yōu)先考慮使用最多的模塊,并為它們分配最小的ID
new webpack.optimize.OccurenceOrderPlugin(),
// 模塊熱替換插件
new webpack.HotModuleReplacementPlugin(),
// 允許錯誤不打斷程序
new webpack.NoErrorsPlugin(),
// 全局掛載插件
new webpack.ProvidePlugin({
$:"jquery",
jQuery:"jquery",
"window.jQuery":"jquery"
})
];
// vue里的css也要單獨(dú)提取出來
config.vue = {
loaders: {
css: ExtractTextPlugin.extract("css")
}
};
// 啟用source-map,開發(fā)環(huán)境下推薦使用cheap-module-eval-source-map
config.devtool='cheap-module-eval-source-map';
// 為了實(shí)現(xiàn)熱加載,需要動態(tài)向入口配置中注入 webpack-hot-middleware/client ,路徑相對于本文件所在的位置
// var devClient = 'webpack-hot-middleware/client';
// 為了修改html文件也能實(shí)現(xiàn)熱加載,需要修改上面的devClient變量,引入同級目錄下的dev-client.js文件
var devClient = './build/dev-client';
// Object.keys()返回對象的可枚舉屬性和方法的名稱
Object.keys(config.entry).forEach(function (name, i) {
var extras = [devClient];
config.entry[name] = extras.concat(config.entry[name]);
})
module.exports = config;
3.webpack.prod.config.js(生產(chǎn)環(huán)境下的配置文件)
// 引入依賴模塊
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
// 引入基本配置
var config = require('./webpack.config');
// 重新配置插件項(xiàng)
config.plugins = [
// 位于生產(chǎn)環(huán)境下
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
// 自動生成html插件,如果創(chuàng)建多個HtmlWebpackPlugin的實(shí)例,就會生成多個頁面
new HtmlWebpackPlugin({
// 生成html文件的名字,路徑相對于輸出文件所在的位置
filename: '../../html/index.html',
// 源文件,路徑相對于本文件所在的位置
template: path.resolve(__dirname, '../src/pages/index.html'),
// 需要引入entry里面的哪幾個入口,如果entry里有公共模塊,記住一定要引入
chunks: ['vendors','special','index'],
// 要把<script>標(biāo)簽插入到頁面哪個標(biāo)簽里(body|true|head|false)
inject: 'body',
// 生成html文件的標(biāo)題
title:'',
// hash如果為true,將添加hash到所有包含的腳本和css文件,對于解除cache很有用
// minify用于壓縮html文件,其中的removeComments:true用于移除html中的注釋,collapseWhitespace:true用于刪除空白符與換行符
}),
// 提取css單文件的名字,路徑相對于輸出文件所在的位置
new ExtractTextPlugin("../css/[name].[contenthash].css"),
// 提取入口文件里面的公共模塊
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
filename: 'vendors.js',
}),
// 壓縮js代碼
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
// 排除關(guān)鍵字,不能混淆
except:['$','exports','require']
}),
// 為組件分配ID,通過這個插件webpack可以分析和優(yōu)先考慮使用最多的模塊,并為它們分配最小的ID
new webpack.optimize.OccurenceOrderPlugin(),
// 全局掛載插件,當(dāng)模塊使用這些變量的時候,wepback會自動加載,區(qū)別于window掛載
new webpack.ProvidePlugin({
$:"jquery",
jQuery:"jquery",
"window.jQuery":"jquery"
})
];
// vue里的css也要單獨(dú)提取出來
config.vue = {
loaders: {
css: ExtractTextPlugin.extract("css")
}
};
// 開啟source-map,生產(chǎn)環(huán)境下推薦使用cheap-source-map或source-map,后者得到的.map文件體積比較大,但是能夠完全還原以前的js代碼
config.devtool='source-map';
// 關(guān)閉source-map
// config.devtool=false;
module.exports = config;
4.dev-server.js(服務(wù)器配置文件)
// 引入依賴模塊
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.dev.config.js');
// 創(chuàng)建一個express實(shí)例
var app = express();
// 對網(wǎng)站首頁的訪問返回 "Hello World!" 字樣
app.get('/', function (req, res) {
res.send('Hello World!');
});
// 調(diào)用webpack并把配置傳遞過去
var compiler = webpack(config);
// 使用 webpack-dev-middleware 中間件,搭建服務(wù)器
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath,
stats: {
colors: true,
chunks: false
}
})
// 使用 webpack-hot-middleware 中間件,實(shí)現(xiàn)熱加載
var hotMiddleware = require('webpack-hot-middleware')(compiler);
// 為了修改html文件也能實(shí)現(xiàn)熱加載,使用webpack插件來監(jiān)聽html源文件改變事件
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
// 發(fā)布事件
hotMiddleware.publish({ action: 'reload' });
cb();
})
});
// 注冊中間件
app.use(devMiddleware);
app.use(hotMiddleware);
// 監(jiān)聽 8888 端口,開啟服務(wù)器
app.listen(8888, function (err) {
if (err) {
console.log(err);
return;
}
console.log('Listening at http://localhost:8888');
})
5.dev-client.js(配合dev-server.js監(jiān)聽html文件改動也能夠觸發(fā)自動刷新)
// 引入 webpack-hot-middleware/client
var hotClient = require('webpack-hot-middleware/client');
// 訂閱事件,當(dāng) event.action === 'reload' 時執(zhí)行頁面刷新
hotClient.subscribe(function (event) {
if (event.action === 'reload') {
window.location.reload();
}
})
五、為了不必每次構(gòu)建項(xiàng)目都要輸入webpack --display-modules --display-chunks --config build/webpack.config.js這條長命令,我們在package.js文件中修改“scripts”項(xiàng):
"scripts": {
"build":"webpack --display-modules --display-chunks --config build/webpack.config.js",
"dev":"node ./build/dev-server.js"
}
注意:package.js中不能有注釋。
這樣,我們就可以通過執(zhí)行 npm run build 來進(jìn)行構(gòu)建,同時還增加了一條開啟開發(fā)服務(wù)器的命令 npm run dev。
六、網(wǎng)上很多人講解webpack配置是按“先……然后……”的邏輯往下走,以及每走一步會說明走這一步的原因是什么,配完之后的結(jié)果是什么,出了問題該怎么解決,這種撰文方式確實(shí)幫了很多入門webpack的小白們(譬如我)很大的忙。所以這里我就省略了這些步驟,而是直接將最后一步的配置結(jié)果展現(xiàn)出來給大家看,并且附上了詳細(xì)的注釋(寫得嘔心瀝血啊~)供大家理解,以后不出意外應(yīng)該會出webpack構(gòu)建vue的進(jìn)階篇,敬請期待~
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
用innerHTML?。Ψ柛敝到o文本框后會變成&amp;的方法
用innerHTML?。Ψ柛敝到o文本框后會變成&amp;的方法...2007-07-07
Bootstrap教程JS插件滾動監(jiān)聽學(xué)習(xí)筆記分享
這篇文章主要為大家分享了Bootstrap教程JS插件滾動監(jiān)聽學(xué)習(xí)筆記,內(nèi)容很詳細(xì),感興趣的小伙伴們可以參考一下2016-05-05
JS+CSS實(shí)現(xiàn)淡入式焦點(diǎn)圖片幻燈切換效果的方法
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)淡入式焦點(diǎn)圖片幻燈切換效果的方法,實(shí)例分析了javascript操作圖片、css等元素實(shí)現(xiàn)幻燈片的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-02-02
javaScript嗅探執(zhí)行神器-sniffer.js
本文主要介紹了javaScript嗅探執(zhí)行神器-sniffer.js的相關(guān)知識。具有很好的參考價值,下面跟著小編一起來看下吧2017-02-02

