由淺入深支持更多功能javascript
1.安裝最新版本的node.js和NPM,並瞭解NPM基本用法。css
2.建立一個目錄demo。使用npm 初始化配置: npm init ,執行後會有一系列選項,可按回車快速確認,在demo中生成一個package.json文件。html
3.局部安裝webpack : npm install webpack --save-devvue
--save-dev 會做爲開發依賴來安裝webpack。安裝成功後,在package.json中會多一項配置java
"devDependencies": { "webpack": "4.6.0" }
4.接着須要安裝webpack-dev-server,它能夠在開發環境中提供不少服務,好比啓動一個服務器,熱更新,接口代理等node
局部安裝: npm install webpack-dev-server --save-devwebpack
5.在demo下建立一個js文件:webpack.config.js初始化內容:es6
var config = { }; module.exports = config;
6.在package.json的script裏增長一個快速啓動webpack-dev-server服務的腳本:web
{ //... "scripts":{ "test":*****, "dev":"webpack-dev-server --open --config webpack.config.js" } }
當運行npm run dev就會執行webpack-dev-server --open --config webpack.config.js命令。其中--config是指向webpack-dev-server 讀取的配置文件路徑,這裏直接讀取咱們在上一步建立的webpack.config.js文件。--open會在執行命令是打開瀏覽器頁面,默認地址是127.0.0.1:8080,不過ip和端口均可以配置。npm
"dev":"webpack-dev-server --host 172.172,172.1 --port 8888 --open --config webpack.config.js"
通常用默認的本機地址就能夠。
7.在demo目錄下新建一個空的main.js做爲入口的文件,而後在webpack.config.js中進行入口的輸出和配置:
var path = require('path'); var config = { entry: { main: './main' }, output: { path: path.join(__dirname, '/dist'), publicPath: './dist', filename: 'main.js' } }; module.exports = config;
entry中的main就是咱們配置的單入口,webpack會從main.js文件開始工做。output中path選項用來存放打包後文件的輸出目錄,必填項。publicPath是資源文件引用目錄,若是在cdn上,這裏能夠填寫cdn地址。filename用於指定輸出文件的名稱。所以,這裏配置的output意爲打包後的文件會存放在demo/dist/main.js,只在html引入就能夠了。
<body> <div id="app">Hello world</div> <script src="/dist/main.js"></script> </body>
8.運行 npm run dev就能看到hello world字樣。
9.逐步完善配置文件
在webpack的世界中,每一個文件都是一個模塊,好比.css、.js、.html、.jpg、.less等。對於不一樣的模塊須要用不一樣的加載器來處理,而加載器就是webpack最重要的功能。
安裝style-loader和css-loader來處理css樣式。
經過npm 來安裝:
npm install css-loader --save-dev
npm install style-loader --save-dev
安裝完成後再webpack.config.js文件裏面配置Loader,增長對.css文件的處理。
var config = { //..... module:{ rules:[ { test:/\.css$/, use:[ 'style-loader', 'css-loader' ] } ] } };
module對象 的rules屬性中能夠指定一系列的loader,每個loader都必須包含test和use兩個選項。這段的意思是說,當webpack編譯過程當中遇到require()或import語句導入一個後綴名爲.css的文件時,先將它經過css-loader轉換,再經過style-loader轉換,而後繼續打包。use選項的值能夠是數組或字符串,若是是數組,它的編譯順序就是從後往前。
在demo下新建一個style.css文件,並在main.js中導入:
/**style.css**/
#app{
font-size:24px;
color:#f50;
}
//main.js
import './style.css'
從新執行npm run dev能夠看到頁面文字變成了紅色,字號變大。
下面是執行後的html源碼:
能夠看到,css是經過javascript動態建立style標籤來寫入的,這意味着樣式代碼都已經編譯在了mian.js文件裏,可是在實際業務中可能並不但願這樣作,由於項目大了樣式會不少,都放在js裏太佔體積。這時 就要用到webbpack的插件。
webpack的插件功能很強大並且能夠定製。這裏咱們使用一個extract-text-webpack-plugin的插件來把散落在各地的css提取出來,並生成一個main.css的文件,並最終在index.html裏經過link的形式加載它。
10.經過npm 安裝extract-text-webpack-plugin插件:
npm install extract-text-webpack-plugin --save-dev
而後在配置文件中導入插件,並改寫loader配置:
var path = require('path'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var config = { //..... module:{ rules:[ { test:/\.css$/, use:ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'style.loader' }) } ] }, plugin: [ //重命名提取後的css文件 new ExtractTextPlugin("main.css") ] }; module.exports = config;
這個時候運行可能會出現「DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead」相似的報錯,這個是webpack版本問題
使用 sudo npm install extract-text-webpack-plugin@next 安裝4.0就可解決這個問題。
11.單文件組件和vue-loader
在使用webpack構建Vue項目時,可使用一種新的構建模式:.vue單文件組件。在webpack中使用vue-loader就能夠對.vue格式的文件進行處理。
一個.vue文件通常包含3部分,<template>、<script>、<style>
style標籤使用scoped屬性,表示當前的css只在這個組件有效,若是不加,那麼樣式會應用到整個項目。style還能夠結合css預編譯一塊兒使用。好比less處理就能夠寫成<style lang="less">。使用.vue文件須要安裝 vue-loader,vue-style-loader等加載器並作配置。由於要使用es6語法,還需安裝babel和babel-loader等加載器。使用npm 逐個安裝如下依賴:
npm install --save vue
npm install --save-dev vue-loader
npm install --save-dev vue-style-loader
npm install --save-dev vue-template-compiler
npm install --save-dev vue-hot-reload-api
npm install --save-dev babel
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-runtime
12.安裝完成後,在webpack.config.js配置以支持.vue文件和es6的解析。
var path = require('path'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var config = { entry: { main:'./main' }, output: { path: path.join(__dirname, '/dist'), publicPath: '/dist', filename: 'main.js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders :{ css: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'vue-style-loader' }) } } }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'style-loader' }) } ] }, plugins: [ new ExtractTextPlugin("main.css") ] }; module.exports = config;
vue-loader在編譯.vue文件時,會對<template>、<script>、<style>分別處理,因此在vue-loader選項裏多了一項options來進一步對不一樣語言進行配置。好比在對css進行處理時,會先經過css-loader解析,而後把處理結果再交給vue-style-loader處理。當技術棧多樣化時,能夠給<template>、<script>、<style>都指定不一樣的語言,好比<template lang="jade">和<style lang="less">,而後配置loader就能夠了。
13.在demo目錄下新建一個名爲.babelrc的文件,並寫入babel的配置,webpack會依賴此配置文件來使用babel編譯es6代碼:
{ "presets": ["es2015"], "plugins": ["transform-runtime"], "comments": false }
配置好這些後就可使用.vue文件了,每一個.vue文件就表明一個組件,組件之間能夠相互依賴。
14.在demo目錄下新建一個app.vue的文件並寫入如下內容:
<template> <div>Hello {{name}}</div> </template> <script> export default { data() { return { name: "vue.js" } } } </script> <style scoped> div{ color: #f60; font-size: 24px; } </style>
.vue的組件時沒有名稱的,在父組件使用時能夠對它自定義。寫好了組件,就能夠在入口main.js中是用它了。打開main.js,把內容替換下面代碼:
import Vue from 'vue'; //導入app.vue組件 import App from './app.vue'; //建立Vue實例 new Vue({ el: "#app", render: h => h(App) });
render:h => h(App)是es6的寫法,等同於
render:function(h){
return h(App)
}
執行npm run dev,這樣第一個vue工程項目就跑起來了。
bug:這個地方vue-loader升級到15版本以上不兼容。須要退回14版本才兼容。
這裏之因此多了一串data-v-xxx內容,是由於使用了<style scope>功能,若是去掉scope就沒有了。
15.在demo 目錄下新建兩個文件,title.vue和button.vue
title.vue
<template> <h1> <a :href="'#' + title">{{title}}</a> </h1> </template> <script> export default { props:{ title:{ type:String } } } </script> <style scoped> h1 a{ color: #3399ff; font-size: 24px; } </style>
button.vue
<template> <button @click="handleClick" :style="styles"> <slot></slot> </button> </template> <script> export default { props: { color: { type: String, default: '#00cc66' } }, computed:{ styles () { return { background: this.color } } }, methods:{ handleClick:function(e){ this.$emit('click',e); } } } </script> <style scoped> button{ border: 0; outline: none; color: #fff; padding: 4px 8px; } button:active{ position: relative; top: 1px; left: 1px; } </style>
而後改寫根實例app.vue組件,把title.vue和button.vue導入:
<template> <div> <v-title title="Vue組件化"></v-title> <v-button @click="handleClick">點擊按鈕</v-button> </div> </template> <script> //導入組件 import vTitle from './title.vue'; import vButton from './button.vue'; export default { components: { vTitle, vButton }, methods:{ handleClick:function(e){ console.log(e) } } } </script> <style scoped> div { color: #f60; font-size: 24px; } </style>
其中components: {
vTitle,
vButton
}
寫法是es6寫法,等同於:
components: {
vTitle : vTitle,
vButton : vButton
}
導入的組件都是局部註冊的,並且能夠自定義名稱,其餘用法和組件用法一致。
用於生產環境
咱們先對webpack進一步配置,來支持更多的經常使用功能。
安裝 url-loader 和 file-loader來支持圖片,字體等文件:
npm install --save-dev url-loader
npm install --save-dev file-loader
//webpack.config.js
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, loader: 'url-loader?limit=1024' }
當遇到.gif、.png、.ttf等格式文件時,url-loader會把它們一塊兒編譯到dist目錄下,"limit=1024"表示若是這個文件小於1kb,就以base64的形式加載,不會生產一個文件。
找一張圖片,保存爲demo/images/image.png,並在app.vue中加載它:
<template> <div> <v-title title="Vue組件化"></v-title> <v-button @click="handleClick">點擊按鈕</v-button> <p> <img src="./images/image.png" style="width: 300px"> </p> </div> </template>
webpack打包後的產物:
單頁面富應用(SPA)技術,意味着最終只有一個html文件,其他都是靜態資源。實際部署到生產環境,通常都會將html掛載後端程序下,由後端路由渲染這個頁面,將全部的靜態資源(css、js、image、iconfont等)單獨部署到CDN,固然也能夠和後端程序部署在一塊兒,這樣就實現了先後端徹底分離。
在webpack的output選項裏指定了path和publicPath,打完包後,全部的資源都會保存在demo/dist目錄下。
打包會用到下面兩個依賴,使用NPM安裝:
npm install --save-dev webpack-merge
npm install --save-dev html-webpack-plugin
爲了方便開發和生產環境的切換,咱們在demo目錄下再新建一個用於生產環境的配置文件 webpack.prod.config.js
編譯打包,直接執行webpack命令就能夠。在package.json中,再加入一個build的快捷腳本用來打包:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --open --config webpack.config.js", "build": "webpack --progress --hide-modules --config webpack.prod.config.js" },
webpack.prod.config.js的代碼以下:
var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var merge = require('webpack-merge'); var webpackBaseConfig = require('./webpack.config.js'); //清空基本配置的插件列表 webpackBaseConfig.plugins = []; module.exports = merge(webpackBaseConfig, { output: { publicPath: '/dist/', //將入口文件重命名爲帶有20位hash值的惟一文件 filename: '[name].[hash].js' }, plugins: [ new ExtractTextPlugin({ //提取css,並重命名爲帶有20位hash值得惟一文件 filename: '[name].[hash].css', allChunks: true }), //定義當前node環境爲生產環境 new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), //壓縮js new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), //提取模板,並保存入口html文件 new HtmlwebpackPlugin({ filename: '../index_prod.html', template: './index.ejs', inject: false }) ] });
上面安裝的webpack-merge模塊就是用於合併兩個webpack的配置文件,因此prod的配置是在webpack.config.js基礎上擴展的。靜態資源在大部分場景下都有緩存,更新上線後通常都但願用戶能及時地看到內容,因此給打包後的css和js文件都加了20位的hash值,這樣文件名就惟一了,只要不對html文件設置緩存,上線後當即就能夠加載最新的靜態資源。
html-webpack-plugin是用來生成html文件的,它經過template選項累讀取指定的模板index.ejs,而後輸出到filename指定的目錄,也就是說demo/index_prod.html,模板index.ejs動態設置了靜態資源的路徑和文件名。
最後在終端運行npm run build,等一會就會打完包,成功後會在demo目錄下生成一個dist目錄,裏面就是打完包全部的靜態資源。
bug:webpack升級4以上,打包會報錯:
Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.
這是由於新版本把方法移除了。解決辦法1:在script裏面配置
"build": "webpack --mode production"
就會自動打包。
解決辦法2:webpack內置的JS壓縮插件不能使用了,能夠安裝uglifyjs-webpack-plugin插件,使用同其餘非內置插件。