從零開始搭建vue腳手架

零、前言

本文從零開始vu2+webpack4腳手架搭建,各類步驟配置均可從最後的「參考」中得到,採用yarn做爲包管理工具,mac系統,vs code做爲ide開發工具。舒適提示:全部命令執行都是在項目目錄(vue-demo)中執行。根據本教程走一遍(記得看參考中對應的鏈接),webpack4的經常使用插件、加載器基本熟悉,可應付大部分開發。css

1、建立項目

`mkdir vue-demo && cd vue-demo && yarn init`
複製代碼

2、添加配置webpack依賴

  1. yarn add webpack webpack-cli -Dhtml

  2. 配置webpack編譯腳本 vi package.json 新增以下內容:vue

    "scripts": {
        "build": "webpack --config webpack.config.js"
      },
    複製代碼
    1. 建立webpack配置文件 touch webpack.config.js && vi webpack.config.js
    // 配置入口文件與輸出打包文件及路徑
    const path = require('path')
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.join(__dirname, dist),
        filename: 'index.js'
      } 
    }
    複製代碼
  3. 建立入口文件 ./src/index.js: mkdir src && touch ./src/index.jsnode

    console.log('Hello vue2&webpack4.')
    複製代碼
  4. 測試配置 yarn build && node ./dist/bundle.js 驗證dist/bundle.js是否存在,控制檯輸出"Hello vue2&webpack4."字符串即表示成功webpack

3、html-webpack-plugin自動建立html並裝配打包的bundle.js

  1. 添加html-webpack-plugin yarn add html-webpack-plugin -Dgit

  2. 修改webpack.config.js配置github

    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        mode: "development",
        entry: './src/index.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        },
        plugins:[
            new HtmlWebpackPlugin({
                title: 'Vue2 && Webpack4'
            })
        ]
    }
    複製代碼
  3. yarn build 編譯驗證,採用瀏覽器打開dist/index.html,cmd+option+i查看控制檯輸出"Hello vue2&webpack4."字符串web

4、添加vue相關依賴

  1. yarn add vuenpm

  2. yarn add vue-loader vue-template-compiler css-loader -Djson

  3. yarn add url-loader file-loader -D

  4. 修改webpack.config.js配置

    const path = require('path')
    const { VueLoaderPlugin } = require('vue-loader')  
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const config = {
        mode: 'development',
        entry: './src/index.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        },
        plugins:[
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin({
                title: 'Vue2 && Webpack4'
            })
        ],
        // 新增vue-loader配置
        module:{
            rules: [
                {
                    test: /\.vue$/,
                    loader: 'vue-loader'
                },
                {
                    test: /\.css$/,
                    use: ['vue-style-loader', 'css-loader'],
                },
                {
                    test: /\.(png|jpe?g|gif)$/i,
                    use: [
                      {
                        loader: 'url-loader',
                        options: {
                            // 自定義輸出命名規則
                            name: 'resources/[name].[hash:8].[ext]',
                            // 圖片轉爲base64的最大閾值
                            limit: 8192,
                            // 當大於limit時採用file-loader加載器處理,默認便是file-loader
                            fallback: 'file-loader'
                        }
                      }
                    ]
                }
            ]
        }
    }
    module.exports = config
    複製代碼
  5. 建立源碼存放目錄mkdir src/components && mkdir src/api && mkdir src/store && mkdir -p src/assets/images,拷貝2張圖片到src/assets/images目錄下,分別命名以下:bg.jpg logo.png,最好有一張大於8092kb(見上配置)

  6. 建立src/components/app.vue

    <template>
    <div>
        <h2>{{title}}</h2>
        <img src="../assets/images/logo.png" width="50px" height="50px"/>
        <div class="bg">
            我在背景圖上
        </div>
    </div>
    </template>
    <script>
    export default {
        data() {
            return {
                title: 'Hello vue2&&webpack4....3'
            }
        }
    }
    </script>
    <style scoped>
        .bg {
            width: 500px;
            height: 500px;
            background-image: url('../assets/images/bg.jpg');
        }
    </style>
    複製代碼
  7. 編譯yarn build

  8. 瀏覽器打開dist/index.html能夠到展現Hello vue2&&webpack4. logo圖以及背景圖

5、postcss加載器安裝配置

`yarn add -D postcss-loader autoprefixer`
複製代碼
  1. 修改webpack.config.js配置
    {
        test: /\.css$/,
        exclude: /node_modules/,
        // 舒適提示:webpack調用順序是從右到左
        use: ['vue-style-loader', 'css-loader', 'postcss-loader']
    },
    複製代碼
  2. 建立postcss的配置文件postcss.config.js,啓用autoprefixer插件
    module.exports = {
    plugins: [
      // require('precss'),
      require('autoprefixer')
    ]
    複製代碼

}

3. 修改src/components/app.vue

複製代碼
```
  1. yarn build,打開dist/bundle.js,搜索test-prefix字符串,找到類定義,可驗證user-select自動添加了瀏覽器前綴
    test-prefix[data-v-6c0a0fc1]{\\n    display: flex;\\n  
    -webkit-user-select: none;\\n       -moz-user-select: none;\\n    
    -ms-user-select: none;\\n            user-select: none;\\n}\\n\", \"\"] 複製代碼

6、安裝配置mini-css-extract-plugin

  1. yarn add mini-css-extract-plugin --save-dev
  2. 修改webpack配置
// 新增
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// 修改
{
    test: /\.css$/,
    use: [
      MiniCssExtractPlugin.loader,//devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
      'css-loader',
      'postcss-loader'
    ],
},
// {
//     test: /\.css$/,
//     exclude: /node_modules/,
//     // 舒適提示:webpack調用順序是從右到左
//     use: ['vue-style-loader', 'css-loader', 'postcss-loader'],
// },

// 新增
new MiniCssExtractPlugin({
    // Options similar to the same options in webpackOptions.output
    // both options are optional
    filename: '[name].css',//devMode ? '[name].css' : '[name].[hash].css',
    chunkFilename: '[id].css'// devMode ? '[id].css' : '[id].[hash].css',
  })
複製代碼
  1. 驗證,yarn build,查看dist目錄下生成的main.css文件,內容以下:
    .bg[data-v-6c0a0fc1] {
        width: 500px;
        height: 200px;
        background-image: url(resources/bg.dedfb384.jpg);
    }
    /*   新增  */
    .test-prefix[data-v-6c0a0fc1]{
        display: flex;
        -webkit-user-select: none;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none;
        color: red;
    }
    複製代碼
    dist/bundle.js搜索test-prefix,只能看到引用而沒有此類定義,即被提取到main.css文件

7、安裝配置babel-loader

  1. yarn add babel-loader @babel/core @babel/preset-env webpack -D

  2. yarn add @babel/polyfill

  3. 修改webpack配置

    {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          // 配置也可獨立到.babelrc文件中
          options: {
            presets: ['@babel/preset-env']
          }
        }
    },
    複製代碼
  4. 修改src/components/app.vue

<template>
    <div>
        <h2>{{title}}</h2>
        <!-- 新增 -->
        <div class="test-prefix">
            <p>我就測試一下,看看而已,我是紅色哦</p>
        </div>
        <img src="../assets/images/logo.png" width="50px" height="50px"/>
        <div class="bg">
            我在背景圖上
            <div v-for="(item, index) in list" :key="index">
                {{item}}
            </div>
        </div>
        <button @click="onClickButton">測試ES6 ES7語法</button>
    </div>
</template>
<script>
require('@babel/polyfill')
class Echo {
    constructor(msg){
        this.msg = msg
    }
    print() {
        console.log(this.msg)
    }
    getMsg() {
        return this.msg
    }
}
export default {
    data() {
        return {
            title: 'Hello vue2&&webpack4....3',
            list: ['test1', 'test2', 'test3']
        }
    },
    methods: {
        onClickButton(e) {
            let echo = new Echo('我是ES6語法class構建的對象哦')
            echo.print();
            alert(echo.getMsg())
            let sum = 2 ** 10
            alert(`ES7 求冪運算符(2 ** 10)= ${sum}`)
        },
        // async特性,切記添加require('@babel/polyfill')在前面
        async getA() {
            return new Promise((resolve, rejuect) => {
                console.log('====== getA')
                setTimeout(()=>resolve(`It's timeout.`), 3000) }) } } } </script> <style scoped> .bg { width: 500px; height: 200px; background-image: url('../assets/images/bg.jpg'); } /* 新增 */ .test-prefix{ display: flex; user-select: none; color: red; } </style> 複製代碼
  1. 驗證,yarn build,打開dist/bundle.js文件,搜索onClickButton,可看到函數體裏面的求冪運算**被轉爲了Math.pow函數,如:
onClickButton:function(t){var e=new s("我是ES6語法class構建的對象哦");e.print(),alert(e.getMsg());var n=Math.pow(2,10);alert("求冪運算符(2 ** 10)= ".concat(n))}
複製代碼

8、eslint安裝配置

  1. yarn add -D eslint eslint-plugin-vue
  2. yarn add -D eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
  3. 建立.eslintrc.js文件
module.exports = {
    extends: [
      // add more generic rulesets here, such as:
      // 'eslint:recommended',
      // 'plugin:vue/recommended',
      "plugin:vue/essential"
    ],
    rules: {
      // override/add rules settings here, such as:
      // 'vue/no-unused-vars': 'error'
      'no-console': 'off',
    },
    "plugins": [
    ]
  }

複製代碼
  1. 修改src/components/App.vue
<template>
  <div>
    <h2>{{ title }}</h2>
    <div class="test-prefix">
      <p>我就測試一下,看看而已,我是紅色哦</p>
    </div>
    <img
      src="../assets/images/logo.png"
      width="50px"
      height="50px"
    />
    <div class="bg">
      我在背景圖上
    </div>
    <button v-bind:click="onClickButton">
      測試ES6語法
    </button>
    <!-- idx沒使用,給eslint-plugin-vue檢測 -->
    <div v-for="(item, idx) in list" :key="item.id">
      <p>{{item}}{{}}</p>
    </div>
  </div>
</template>
<script>
class Echo {
  constructor (msg) {
    this.msg = msg
  }
  print () {
    console.log(this.msg)
  }
  getMsg () {
    return this.msg
  }
}
export default {
  data () {
    return {
      title: 'Hello vue2&&webpack4....3',
      list: ['test1', 'test2', 'test3']
    }
  },
  methods: {
    onClickButton (e) {
      // js標準風格字符串必須適應'號,故意爲之 let echo = new Echo("我是ES6語法class構建的對象哦") echo.print() alert(echo.getMsg()) let sum = 2 ** 10 alert(`求冪運算符(2 ** 10)= ${sum}`) } } } </script> <style scoped> .bg { width: 500px; height: 200px; background-image: url('../assets/images/bg.jpg'); } /* 新增 */ .test-prefix{ display: flex; user-select: none; color: red; } </style> 複製代碼
  1. 在package.json的scripts中添加命令:"lint": "eslint src/**/*.{js,vue}",
  2. 驗證,yarn lint,能夠看到輸出2處錯誤都是src/components/App.vue中引發的,根據報錯緣由修改後,再運行正常便可。舒適提示:可安裝ide插件自動提示修復eslint錯誤。

9、安裝配置clean-webpack-plugin

  1. yarn add clean-webpack-plugin --save-dev

  2. 修改webpack.config.js配置

    // 引入插件
    const CleanWebpackPlugin = require('clean-webpack-plugin')
    
    // 修改
    plugins:[
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            title: 'Vue2 && Webpack4',
            // template: './src/index.html'
        }),
        // 新增
        new CleanWebpackPlugin([
            'dist'
          ], {
            // Absolute path to your webpack root folder (paths appended to this)
            // Default: root of your package
            root:  __dirname,
            exclude:  [],
            // Write logs to console.
            verbose: true,
            // Use boolean "true" to test/emulate delete. (will not remove files).
            // Default: false - remove files
            dry: false,
            // If true, remove files on recompile. 
            // Default: false
            watch: false,
          })
        ],
    複製代碼
  3. 驗證,yarn build,可先看到刪除dist目錄而後再生成dist目錄內容

10、build前eslint檢測

  1. yarn add eslint-loader

  2. 修改webpack配置

    {
        enforce: "pre",
        test: /\.(vue|js)$/,
        exclude: /node_modules/,
        loader: "eslint-loader"
      }
    複製代碼
  3. 不修復步驟十執行yarn lint出錯的代碼,執行yarn build會出現一樣的錯誤build前進行了eslint檢測,根據錯誤緣由修復後再執行便可正常打包。

11、開發生產環境配置

  1. mkdir build && mv webpack.config.js build/webpack.config.js && touch build/webpack.config.dev.js && touch build/webpack.config.prod.js

  2. yarn add -D webpack-merge

  3. 抽離公共邏輯在webpack.config.js,開發特性配置放在build/webpack.config.dev.js,生產特性配置放在build/webpack.config.dev.js

  4. 修改三文件內容以下:

    // build/webpack.config.js
    const path = require('path')
    const { VueLoaderPlugin } = require('vue-loader')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const CleanWebpackPlugin = require('clean-webpack-plugin')
    
    const config = {
      entry: path.resolve(__dirname, '../src/index.js'), // 爲消除異議,明確指定
      //entry: './src/index.js',// 相對路徑這裏不是基於本文件的位置,而是工程目錄,因此不是../src/index.js
      output: {
          filename: 'bundle.js',
          path: path.resolve(__dirname, 'dist')
      },
      plugins:[
          new VueLoaderPlugin(),
          new HtmlWebpackPlugin({
              title: 'Vue2 && Webpack4',
              // template: './src/index.html'
          }),
          new CleanWebpackPlugin([
              path.resolve(__dirname, 'dist')
            ], {
              // Absolute path to your webpack root folder (paths appended to this)
              // Default: root of your package
              root:  __dirname,
              exclude:  [],
              // Write logs to console.
              verbose: true,
              // Use boolean "true" to test/emulate delete. (will not remove files).
              // Default: false - remove files
              dry: false,
              // If true, remove files on recompile.
              // Default: false
              watch: false,
            })
      ],
      // 新增vue-loader配置
      module:{
        rules: [
            {
              enforce: "pre",
              test: /\.(vue|js)$/,
              exclude: /node_modules/,
              loader: "eslint-loader"
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                  loader: 'babel-loader',
                  // 配置也可獨立到.babelrc文件中
                  options: {
                    presets: ['@babel/preset-env']
                  }
                }
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
    
            // {
            //     test: /\.css$/,
            //     exclude: /node_modules/,
            //     // 舒適提示:webpack調用順序是從右到左
            //     use: ['vue-style-loader', 'css-loader', 'postcss-loader'],
            // },
            {
                test: /\.(png|jpe?g|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // 自定義輸出命名規則
                            name: 'resources/[name].[hash:8].[ext]',
                            // 圖片轉爲base64的最大閾值
                            limit: 8192,
                            // 當大於limit時採用file-loader加載器處理,默認便是file-loader
                            fallback: 'file-loader'
                        }
                    }
                ]
            }
          ]
      },
    
      // webpack will automatically split chunks based on these conditions:
      // New chunk can be shared OR modules are from the node_modules folder
      // New chunk would be bigger than 30kb (before min+gz)
      // Maximum number of parallel requests when loading chunks on demand would be lower or equal to 5
      // Maximum number of parallel requests at initial page load would be lower or equal to 3
      // When trying to fulfill the last two conditions, bigger chunks are preferred.
      // 默認配置
      optimization: {
          splitChunks: {
            chunks: 'async',
            minSize: 30000,
            maxSize: 0,
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            automaticNameDelimiter: '~',
            name: true,
            cacheGroups: {
              vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: -10
              },
              default: {
                minChunks: 2,
                priority: -20,
                reuseExistingChunk: true
              }
            }
          }
      }
    }
    module.exports = config
    複製代碼
    // build/webpack.config.dev.js
    const baseConfig = require('./webpack.config.js')
    const webpackMerge = require('webpack-merge')
    const MiniCssExtractPlugin = require("mini-css-extract-plugin")
    
    const config = webpackMerge.smart(baseConfig, {
        mode: 'development',
        plugins: [
          new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: '[name].css',//devMode ? '[name].css' : '[name].[hash].css',
            chunkFilename: '[id].css'// devMode ? '[id].css' : '[id].[hash].css',
          })
        ],
        module:{
          rules: [
            {
              test: /\.css$/,
              use: [
                'vue-style-loader',//devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
                'css-loader',
                'postcss-loader'
              ],
            },
          ]
        }
    })
    module.exports = config
    複製代碼
// build/webpack.config.js
const baseConfig = require('./webpack.config.js')
const webpackMerge = require('webpack-merge')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const config = webpackMerge.smart(baseConfig, {
    mode: 'production',
    plugins: [
      new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // both options are optional
        filename: '[name].[hash].css',
        chunkFilename: '[id].[hash].css',
      })
    ],
    module:{
      rules: [
        {
          test: /\.css$/,
          use: [
            MiniCssExtractPlugin.loader,//devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
            'css-loader',
            'postcss-loader'
          ],
        },
      ]
    }
})
module.exports = config
複製代碼
// 修改package.json
"scripts": {
    "lint": "eslint src/**/*.{js,vue}",
    "build": "yarn build:prod",
    "build:prod": "webpack --config ./build/webpack.config.prod.js",
    "build:dev": "webpack --config ./build/webpack.config.dev.js"
  },
複製代碼
  1. 驗證,yarn build:prod打包生產環境,yarn build:dev打包開發環境,可對比兩次打包build/dist下生成的內容

  2. 開發環境配置服務,以及熱更新

    • yarn add -D webpack-dev-server

    • 修改build/webpack.config.dev.js

      devServer: {
        open: true,
        contentBase: path.resolve(__dirname, 'dist'),
        compress: false,
        port: 9000,
        hot: true
      },
      plugins: [
        new MiniCssExtractPlugin({
          // Options similar to the same options in webpackOptions.output
          // both options are optional
          filename: '[name].css',//devMode ? '[name].css' : '[name].[hash].css',
          chunkFilename: '[id].css'// devMode ? '[id].css' : '[id].[hash].css',
        }),
        new webpack.HotModuleReplacementPlugin()
      ],
      複製代碼
    • 修改package.json

      "scripts": {
          "lint": "eslint src/**/*.{js,vue}",
          "build": "yarn build:prod",
          "build:prod": "webpack --config ./build/webpack.config.prod.js",
          "build:dev": "webpack --config ./build/webpack.config.dev.js",
          "start": "webpack-dev-server --progress --config ./build/webpack.config.dev.js"
        },
      複製代碼
    • 驗證:yarn start, 成功後自動利用默認瀏覽器打開build/dist/index.html,修改src/components/App.vue的樣式或內容,保存即會自動打包同步到打開頁面。

12、總結

本文主要根據各個需求點的官網指導例子進行編寫,基本無錯進行到底。因此文檔仍是一手的好。本文demo已上傳到git。歡迎交流start。
複製代碼

十3、參考

  1. yarn
  2. webpack
  3. html-webpack-plugin
  4. vue
  5. vue-loader
  6. css-loader
  7. postcss
  8. autoprefixer
  9. url-loader
  10. file-loader
  11. mini-css-extract-plugin
  12. webpack optimization
  13. split-chunks-plugin
  14. babel-loader
  15. vue eslint
  16. eslint-config-standard
  17. JavaScript Standard Style
  18. eslint-loader
  19. clean-webpack-plugin
  20. webpack-merge
  21. webpack-dev-server
  22. devserver配置
相關文章
相關標籤/搜索