.
├── README.md
├── build
│ ├── devtool.js // 服務配置
│ ├── entry.js // 獲取全部的入口路徑
│ ├── output.js // 輸出
│ ├── plugins.js // 配置插件
├── package.json
├── webpack.config.dev.js // 開發環境配置
├── webpack.config.js // 生產環境配置
└── src
├── assets // 靜態目錄
│ ├── less // 基本樣式和基礎依賴
│ ├── mixin.less
│ ├── reset.less
│ ├── variable.less
│ ├── images // 圖片
│ ├── home
│ ├── home.png
│ ├── index.png
│ ├── about.png
│ ├── fonts // 字體
│ ├── a.woff
├── components // 組件
│ ├── button.vue
├── entry // 入口js
│ ├── home
│ ├── home.js
│ ├── index.js
│ ├── about.js
├── page // 頁面模塊
│ ├── home
│ ├── home.vue
│ ├── index.vue
│ ├── about.vue複製代碼
.
├── dist
├── css
├── html
├── js
├── images
├── fonts
├── vendor複製代碼
在命令面板輸入以下命令可建立新的目錄:mkdir vue2-webpack3css
2.1 直接在cli裏輸入命令 cd vue2-webpack3 進入項目
2.2 而後輸入命令 npm init,而後依次輸入相關的信息後輸入yes保存相關的項目信息
2.3 這時候項目裏多了一個package.json文件,這個文件裏保存了咱們項目相關的一些信息,具體狀況能夠移步 package.json說明文檔html
你們都知道,webpack的配置文件主要由:entry,output,module,plugins,devtool等幾部分構成,爲了方便管理(若是全在一個文件內,隨着項目的龐大會致使配置頁面的內容過多),我單獨爲除了module之外的幾個屬性創建了文件 前端
由於咱們是多頁面應用,因此咱們的入口文件確定是很是多的,爲了方便獲取全部的入口文件,咱們能夠利用Node的fs文件系統來獲取entry目錄下的全部入口文件的路徑,代碼以下:vue
const fs = require('fs');
const path = require('path');
const directory = path.resolve(__dirname, '../src/entry') ;
const entryList = {};
(getEntry = (dir) => {
const entryArr = fs.readdirSync(dir);
let pathName,
filePath;
entryArr.forEach(function(filename) {
filePath = dir + '/' + filename;
if(fs.statSync(filePath).isDirectory()) {
getEntry(filePath);
} else {
pathName = filePath.split('entry/')[1].replace('.js', '');
entryList[pathName] = filePath;
}
})
})(directory)
module.exports = entryList複製代碼
簡單的解析下這段代碼,主要是利用到了fs.readdirSync和fs.statSync兩個方法。fs.readdirSync方法可以根據你提供路徑,獲取該路徑下的全部文件路徑,好比上面代碼中我傳遞的dir(須要注意fs.readdirSync的參數必須是一個絕對路徑,相對路徑沒法獲取),fs.readdirSync會返回entry下全部文件的路徑,而後咱們拿到這些路徑之後,再根據fs.statSync來判斷這個路徑對應的是一個文件仍是一個目錄,若是是目錄,那就再調用一次,直到拿到文件的路徑。node
const path = require('path');
module.exports = {
path: path.resolve(__dirname, '../dist'),
// publicPath: 'http://img.xxx.com',
filename: 'js/[name].js?ver=[hash:6]'
}複製代碼
配置很簡單,path把全部的文件都輸出到dist目錄裏,filename把全部的js文件都輸出到dist/js目錄下,同時[name]對應的是入口文件中的pathName,若是有須要,也能夠對publicPath進行配置,好比靜態單獨打包到了一個服務器上,那麼咱們就須要對靜態的路徑作統一的處理了。webpack
rules: [
{
test: /\.less$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract(['css-loader', 'less-loader'])
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
less: ExtractTextPlugin.extract({
use: ['css-loader', 'less-loader'],
fallback: 'vue-style-loader'
})
}
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(jpg|jpeg|png|gif)$/,
loaders: 'url-loader',
options: {
limit: 10000
}
},
{
test: /\.(woff|woff2|svg|eot|ttf)$/,
use: 'file-loader'
}
]複製代碼
loader的配置很簡單,可是須要注意幾個問題。
1)我指望的是可以把vue組件中的樣式和less的樣式單獨抽離到css文件中,因此須要利用extract-text-webpack-plugin這個插件,後面會講到這個插件的使用
2)我指望可以利用插件自動補齊css樣式的前綴,因此引入了postcss-loader轉換器和autoprefixer規則,關於自動補齊的配置,我直接新建個postcss.config.js,而後作了以下簡單的配置:git
module.exports = {
plugins: {
'autoprefixer': {}
}
}複製代碼
如此配置之後,項目編譯less的時候會默認讀取該配置文件的內容並根據內容進行後續的處理。
3)我還指望可以在開發的時候用上es6語法,因此咱們須要依賴babel來實現轉譯,webpack中也有babel-loader來作這個事情,咱們須要執行下面的命令來安裝相關的插件:es6
npm i babel-loader babel-core babel-preset-env babel-plugin-transform-runtime --save-dev
npm i babel-runtime --save複製代碼
安裝完後,新建一個.babelrc文件用來配置babel,代碼以下:github
{
presets: [
[
'env',
{
'targets': {
'browsers': ['last 2 versions', 'ie >= 8']
}
}
]
],
plugins: ['transform-runtime']
}複製代碼
簡單說下配置
presets的做用主要是告訴babel用哪一個語法版原本進行轉譯(其實presets就是一堆插件的集合),好比說常見的是babel-preset-es2015,配置以下:web
{
presets: ['es2015']
}複製代碼
按照這個配置babel會將全部的屬於es2015正式版本的語法轉譯爲es5的語法,那麼一些es2016,es2017之類的語法是沒法被轉譯的,並且如今一些現代瀏覽器對於es2015+的支持也愈來愈好,有時候也並非全部的語法都須要轉譯,因此babel推出了新的配置,也就是.babelrc的配置,‘env’這個配置能夠指定咱們指望轉譯最低兼容的瀏覽器,好比這裏配置的是瀏覽器最新的兩個版本和ie8以上的版本,並且對於es2015+的語法也是一樣支持的。
plugins的做用很簡單就是引入插件,這裏引入了個transform-runtime的插件,它的做用在文章結束時會提到。
1)由於是多頁面項目,因此咱們的html頁面都須要前端自行建立,爲了不進行這些無用的重複操做,我引入了html-webpack-plugin插件,代碼以下:
const entry = require('./entry');
let configPlugins = [];
// 根據入口js數組生成頁面
Object.keys(entry).forEach((item) => {
config = {
filename: '../dist/html/' + item + '.html',
template: path.resolve(__dirname, '../src/index.html'),
chunks: [item]
}
configPlugins.push(new HtmlWebpackPlugin(config));
})複製代碼
首先要將入口路徑數組引入進來,由於html-webpack-plugin插件的用法就是實例化一次就會生成一個頁面,因此咱們對entry的key進行了循環,在每一次的循環中,根據key的信息生成config,而後實例化HtmlWebpackPlugin插件,如此就能夠根據entry生成咱們想要的html目錄和頁面
2)上面講到了extract-text-webpack-plugin插件提取css並生成css文件,配置代碼以下:
new ExtractTextPlugin({
filename: 'css/[name].css'
})複製代碼
該配置會根據入口的目錄結構和文件名稱在css中生成對應的結構和css文件,[name]一樣取決於pathName
3)生成了css文件後,我還指望可以對通用的css和js進行提取,因此引入了CommonsChunkPlugin,這個插件提供了對chunk中公共的部分進行提取並生成文件的能力,配置以下:
new webpack.optimize.CommonsChunkPlugin({
name: 'reset',
filename: 'vendor/common.js',
minChunks: 3
})複製代碼
第一個name屬性決定了提取出來的公共css文件的名稱,這個reset.css文件會生成到css目錄下
第二個filename屬性決定了公共js的目錄和名稱,該common.js會生成到vendor目錄下
第三個minChunks決定了當有多少個入口文件都含有該模塊會對該模塊進行抽離,我設置爲3,意味着只有當至少3個入口js中都擁有某個相同的部分,纔會對該部分進行提取。
ps:在提取的時候要注意個問題,CommonsChunkPlugin只提供了提取公用部分並生成文件的能力,而並無提供往html頁面中自動生成公共文件引入的能力,全部咱們須要在模板文件中默認引入公共文件。
4)熱更新功能對於任何一個開發人員來講確定是必不可少的,webpack.HotModuleReplacementPlugin插件提供了這個能力,不過在使用這個插件以前,咱們要先安裝個webpack-dev-server插件,兩個插件結合才能夠實現這個熱更新的功能。
5)clean-webpack-plugin插件也是必不可少的,它可以在每次編譯完成以前先幫助咱們刪除指定的目錄以及目錄下全部的文件,這種作法可以幫助咱們確保每次生成的代碼都是最新的。配置代碼以下:
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})複製代碼
resolve: {
extensions: ['.js', '.vue', '.less'],
alias: {
less$: path.resolve(__dirname, 'src/assets/less'),
components$: path.resolve(__dirname, 'src/components')
}
}複製代碼
extensions的做用主要是方便咱們在引入別的文件時能夠省略後綴
alias的做用是設置一些路徑的別名,那麼在引入別的文件的時候,就能夠利用該別名來替代冗長的路徑
ps:這裏提一下path.resolve,爲何要使用它,是爲了保證全部模塊引入時地址的統一,畢竟項目的結構是有各類層級的,若是不進行統一,那麼不一樣結構的模塊引入時的路徑也會不同。
var path = require('path');
module.exports = {
contentBase: path.resolve(__dirname, '../dist'),
host: 'we.cli', // 別忘了配置host哦
port: 8001, // 端口8001
inline: true, // 能夠監控js變化
hot: true, // 熱啓動
compress: true,
watchContentBase: false
};複製代碼
1)壓縮css
這個比較簡單,只須要在每一個css-loader後面增長一個minimize參數就好了,以下:
{
test: /\.less$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract(['css-loader?minimize', 'less-loader'])
}複製代碼
2) 壓縮js
對js的壓縮須要依賴webpack.optimize.UglifyJsPlugin插件,咱們將plugins.js插件複製一個副本,重命名爲plugins.prod.js,而後引入webpack.optimize.UglifyJsPlugin插件,配置以下:
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})複製代碼
3) 壓縮html頁面
咱們還能夠對html頁面進行壓縮,以達到進一步減小頁面體積的效果,而HtmlWebpackPlugin插件自己已經具有這個能力,新增個minify配置便可,配置以下:
Object.keys(entry).forEach((item) => {
config = {
filename: '../dist/html/' + item + '.html',
template: path.resolve(__dirname, '../src/index.html'),
chunks: [item],
minify: {
// 移除HTML中的註釋
removeComments: true,
// 刪除空白符與換行符
collapseWhitespace: true
}
}
configPlugins.push(new HtmlWebpackPlugin(config));
})複製代碼
好了,經歷了這些步驟之後,項目就構建完了。有興趣的能夠到github上clone代碼下來運行看看,地址: github.com/FedWithMori…
從babel的官網你能夠看到babel-preset-es2015其實就是包含了如下這些插件的集合:
transform-es2015-arrow-functions
transform-es2015-block-scoped-functions
transform-es2015-block-scoping
transform-es2015-classes
transform-es2015-computed-properties
transform-es2015-constants
transform-es2015-destructuring
transform-es2015-for-of
transform-es2015-function-name
transform-es2015-literals
transform-es2015-modules-commonjs
transform-es2015-object-super
transform-es2015-parameters
transform-es2015-shorthand-properties
transform-es2015-spread
transform-es2015-sticky-regex
transform-es2015-template-literals
transform-es2015-typeof-symbol
transform-es2015-unicode-regex
transform-regenerator
經過這個咱們能夠知道,不必定要引入babel-preset-es2015,你也能夠針對某個特別的新特性進行單獨的轉譯配置
答案能夠參考下 segmentfault.com/q/101000000… 的高分回答
大概的做用就是在編譯的時候默認會使用babel-runtime的工具函數,從而減小編譯後的代碼量
webpack文檔:doc.webpack-china.org/concepts/
webpack loader:doc.webpack-china.org/loaders/
webpack插件:doc.webpack-china.org/plugins/
Babel的presets和plugins配置解析:excaliburhan.com/post/babel-…
vue-loader:vue-loader.vuejs.org/zh-cn/start…
最後悄悄打個小廣告,歡迎對前端興趣的朋友加入QQ羣:474471759