wepack從0開始配置vue環(huán)境之一: 基礎(chǔ)配置

github傳送門 dev分支
webpack之二webpack部署優(yōu)化
webpack之三集成vuex和vue-Router
webpack之四集成ssr

  • 創(chuàng)建項目根目錄

  • 在vscode中打開, 在終端中輸入

// cd到項目目錄
cnpm init -y

生成package.json文件

  • 安裝webpack和vue, vue-loader

cnpm i webpack vue-loader webpack@3 -D
cnpm i vue -S
// 安裝完成根據(jù)warning安裝需要的依賴
css-loader vue-template-compiler -D
  • 創(chuàng)建src/app.vue

<template>
  <div class="text">{{text}}</div>
</template>
<script>
export default {
  data () {
    return {
      text: 'abc'
    }
  }
}
</script>
<style>
  .text {
    color: red;
  }
</style>
  • 創(chuàng)建/webpack.config.js

 const path = require('path')

module.exports = {
  entry: path.join(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/, 
        loader: 'vue-loader'
      }
    ]
  }
}
  • 創(chuàng)建/src/index.js 入口js文件

import Vue from 'vue'
import App from './app.vue'

const root = document.createElement('div')
document.body.appendChild(root)

new Vue({
  render: h => h(App)
}).$mount(root)
  • 安裝style-loader和css-loader, url-loader, file-loader, 處理css和圖片文件

cnpm i style-loader url-loader file-loader -D
url-loader依賴于file-loader
module: {
    rules: [
      {
        test: /\.vue$/, 
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(jpg|png|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: '[name]-kay.[ext]'
            }
          }
        ]
      }
    ]
  }
  • 安裝rimraf 在build之前刪除dist目錄

cnpm i rimraf -D
//在package.json.script中添加cli
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "npm run clean && webpack --config webpack.config.js",
    "clean": "rimraf dist"
  },
  • 嵌入stylus: 安裝stylus和stylus-loader

cnpm i stylus stylus-loader -D
{
    test: /\.styl$/,
      use: [
        'style-loader',
        'css-loader',
        'stylus-loader'
      ]
},
  • 使用webpack-dev-server => 開發(fā)環(huán)境

安裝cross-env區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境
配置html模板html-webpack-plugin
配置webpack全局常量插件webpack.DefinePlugin()
變更webpack.config.js結(jié)構(gòu)
在package.json.script里添加dev命令

cnpm i webpac-dev-server@2 cross-env 
 -D
cnpm i html-webpack-plugin -D
//package.json.script
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"

// 代碼
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  resolve: {
    alias: {
      '@assets':path.join(__dirname, 'src/assets')
    }
  },
  entry: path.join(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/, 
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.styl$/,
        use: [
          'style-loader',
          'css-loader',
          'stylus-loader'
        ]
      },
      {
        test: /\.(jpg|png|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: '[name]-kay.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HtmlWebpackPlugin()
  ]
}

if (isDev) {
  config.devServer = {
    port: 8001,
    host: '0.0.0.0',
    overlay: {
      errors: true
    }
  }
}

module.exports = config
// 終端輸入 npm run dev啟動項目
  • webpack-dev-server配合vue熱更替功能實現(xiàn)

使用webpack.HotModuleReplacementPlugin和webpack.NoEmitOnErrorsPlugin
配置devServer.hot = true
css熱更替使用vue-style-loader代替style-loader

if (isDev) {
  config.devServer = {
    port: 8001,
    host: '0.0.0.0',
    overlay: {
      errors: true
    },
    hot: true
  }
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
}
  • 配置source-map方便調(diào)試

config.devtool = '#cheap-module-eval-source-map'
  • 配置jsx和postcss
    安裝postcss-loader, autoprefixer babel-loader, babel-core,babel-preset-env, babel-plugin-transform-vue-jsx,babel-plugin-syntax-jsx, (babel-helper-vue-jsx-merge-props)
    統(tǒng)一cnpm安裝下
    創(chuàng)建/.babelrc, /postcss.config.js并分別配置
// .babelrc
{
  "presets":[
    "env"
  ],
  "plugins": [
    "transform-vue-jsx"
  ]
}
// postcss.config.js
const autoprefixer = require('autoprefixer')
module.exports = {
  plugins: [
    autoprefixer()
  ]
}
// 在devServer里添加babel-loader和postcss-loader
{
        test: /\.js$/,
        loader: 'babel-loader'
      },
      {
        test: /\.jsx$/,
        loader: 'babel-loader'
      },
{
        test: /\.styl$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          'stylus-loader'
        ]
      },
  • 測試jsx-vue模板

新建/src/views/test.jsx

export default {
  data () {
    return {
      test: '這是用jsx語法寫的vue模板'
    }
  },
  render () {
    return (
      <div>
        {this.test}
      </div>
    )
  }
}
  • css文件分離打包成單獨文件

使用extract-text-webpack-plugin
分離打包需要區(qū)分環(huán)境,刪除config目錄上的stylus-loader, 并在對應(yīng)環(huán)境下對應(yīng)loader配置
/webpack.config.js重寫后配置如下

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtartTextPlugin = require('extract-text-webpack-plugin')

const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  resolve: {
    alias: {
      '@assets':path.join(__dirname, 'src/assets')
    }
  },
  entry: path.join(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/, 
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.jsx$/,
        loader: 'babel-loader'
      },
      {
        test: /\.(jpg|png|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: '[name]-kay.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HtmlWebpackPlugin()
  ]
}

if (isDev) {
  config.module.rules.push({
    test: /\.styl$/,
    use: [
      'style-loader',
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true
        }
      },
      'stylus-loader'
    ]
  })
  config.devtool = '#cheap-module-eval-source-map'
  config.devServer = {
    port: 8001,
    host: '0.0.0.0',
    overlay: {
      errors: true
    },
    hot: true
  }
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
} else {
  config.module.rules.push({
    test: /\.styl$/,
    use: ExtartTextPlugin.extract({
      fallback: "style-loader",
      use: [
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            sourceMap: true
          }
        },
        'stylus-loader'
      ]
    })
  })
  config.plugins.push(
    new ExtartTextPlugin({
      filename: 'style.[contenthash:8].css'
    })
  )
}

module.exports = config
  • 單獨打包類庫文件, 實現(xiàn)緩存優(yōu)化性能

修改線上環(huán)境entry選項使用options模式為js文件添加name屬性app和vendor -> 是output中[name]的由來,將開發(fā)環(huán)境的output.filename修改為'bundle.[hash:8].js',
正式環(huán)境修改為: '[name].[chunkhash:8].js'(不可以使用hash, webpack-dev-server會報錯)
hash和chunkhash的區(qū)別:使用hash會讓app和vendor的hash碼一樣是整個應(yīng)用的hash(如果某個js文件改變了, 說有js文件的hash也會跟著改變, 正式環(huán)境就 沒有意義了), 而chunkhash是每一個模塊或者說節(jié)點單獨生成hash,
使用
webpack.optimize.CommonsChunkPlugin({name: 'vendor'})
單獨打包webpack相關(guān)的js代碼:(好處是在有新的模塊加入時候, webpack會給模塊加id, 如果在中間插入會改變之前代碼的id, 這樣會導(dǎo)致hash變化破壞緩存, 需要單獨打包)vendor必須在runtime之前
使用webpack.optimizeCommonsChunkPlugin({name: 'runtime'})
/webpack.config.js修改為:

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtartTextPlugin = require('extract-text-webpack-plugin')

const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  resolve: {
    alias: {
      '@assets':path.join(__dirname, 'src/assets')
    }
  },
  entry: path.join(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.[hash:8].js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/, 
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.jsx$/,
        loader: 'babel-loader'
      },
      {
        test: /\.(jpg|png|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: '[name]-kay.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HtmlWebpackPlugin()
  ]
}

if (isDev) {
  config.module.rules.push({
    test: /\.styl$/,
    use: [
      'style-loader',
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true
        }
      },
      'stylus-loader'
    ]
  })
  config.devtool = '#cheap-module-eval-source-map'
  config.devServer = {
    port: 8001,
    host: '0.0.0.0',
    overlay: {
      errors: true
    },
    hot: true
  }
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
} else {
  config.entry = {
    app: path.join(__dirname, 'src/index.js'),
    vendor: ['vue']
  }
  config.output.filename = '[name].[chunkhash:8].js'
  config.module.rules.push({
    test: /\.styl$/,
    use: ExtartTextPlugin.extract({
      fallback: "style-loader",
      use: [
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            sourceMap: true
          }
        },
        'stylus-loader'
      ]
    })
  })
  config.plugins.push(
    new ExtartTextPlugin({
      filename: 'style.[contenthash:8].css'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime'
    })
  )
}

module.exports = config
  • 生成環(huán)境壓縮js

使用webpack.optimize.UglifyJsPlugin()并配置options.compress.warnings = false, options.output.comments: false

if(isDev) {
  ...
} else {
  ...
config.plugins.push(
    new ExtartTextPlugin({
      filename: 'style.[contenthash:8].css'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime'
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      output: {
        comments: false
      }
    })
  )
}
  • 生成環(huán)境壓縮css

  1. 安裝optimize-css-assets-webpack-plugin@3
  2. 配置生成環(huán)境插件
new OptimizeCssAssetsPlugin({
        assetNameRegExp: /\.css$/,
        cssProcessor: require('cssnano'),
        cssProcessorOptions: { discardComments: { removeAll: true } },
        canPrint: true
      })

這一份簡單webpack配置, 可以讓vue跑起來, 但是遠遠不夠, 接下來還會更新, 能夠部署上線的配置和ssr服務(wù)器端渲染的配置
wepack從0開始配置vue環(huán)境之二: 線上部署配置優(yōu)化
github地址可以下載源碼來研究

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坑夯,一起剝皮案震驚了整個濱河市掉蔬,隨后出現(xiàn)的幾起案子蜘腌,更是在濱河造成了極大的恐慌,老刑警劉巖先巴,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡豆茫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門屋摇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揩魂,“玉大人,你說我怎么就攤上這事炮温』鹇觯” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵柒啤,是天一觀的道長忘分。 經(jīng)常有香客問我,道長白修,這世上最難降的妖魔是什么妒峦? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮兵睛,結(jié)果婚禮上肯骇,老公的妹妹穿的比我還像新娘。我一直安慰自己祖很,他們只是感情好笛丙,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著假颇,像睡著了一般胚鸯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笨鸡,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天姜钳,我揣著相機與錄音,去河邊找鬼形耗。 笑死哥桥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的激涤。 我是一名探鬼主播拟糕,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了送滞?” 一聲冷哼從身側(cè)響起侠草,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎犁嗅,沒想到半個月后梦抢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡愧哟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年奥吩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蕊梧。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡霞赫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肥矢,到底是詐尸還是另有隱情端衰,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布甘改,位于F島的核電站旅东,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏十艾。R本人自食惡果不足惜抵代,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忘嫉。 院中可真熱鬧荤牍,春花似錦、人聲如沸庆冕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽访递。三九已至晦嵌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拷姿,已是汗流浹背惭载。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留跌前,地道東北人棕兼。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓陡舅,卻偏偏與公主長得像抵乓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容