从零开始使用 Webpack 搭建 Vue 开发环境

创建项目

创建项目之前需要安装 Node

先创建一个空目录,在该目录打开命令行,执行 npm init 命令创建一个项目,这个过程会提示输入一些内容,随意输入就行,完成后会自动生成一个 package.json 文件,里面包含了刚才输入的内容,也可以通过执行 npm init -y 跳过那些输入直接创建

创建一个 index.html 页面,由于使用的是 Vue 开发单页应用,通常只需要一个 html 文件就够了,内容也很简单,就一个 div#app

project

  project-name
+ |- index.html
  |- package.json

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>这是标题</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

project

  project-name
  |- index.html
+ |- index.js
  |- package.json
+ |- webpack.config.js

创建一个 index.js 作为项目的主入口,创建一个 webpack.config.js 文件作为 Webpack 的配置文件,内容如下

webpack.config.js

'use strict'

const path = require('path')

module.exports = {
  mode: 'development',
  entry: './index.js',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'dist')
  }
}

entry 是入口文件,指向我们刚才创建的 index.js,output 是输出,输出的文件名也是 index.js,输出文件会放在 dist 目录中

执行 npm install --save-dev webpack webpack-cli 安装 Webpack

--save-dev 表示安装的模块属于开发依赖,会被自动记录在 package.json 中 devDependencies 位置,仅在开发与打包时才会使用到这些模块

在 package.json 文件对应的 scripts 处写入命令

package.json

  {
    "scripts": {
+     "build": "webpack"
    }
  }

执行 npm run build 即可完成打包,默认使用 webpack.config.js 这个配置文件,打包成功后的文件放在 dist 目录里面(这是由配置文件自定义的),目前打包出来的只有一个 index.js 文件,如果需要自己指定配置文件可以在 package.json 里面修改

package.json

  {
    "scripts": {
-     "build": "webpack"
+     "build": "webpack --config webpack.config.js"
    }
  }

启动本地服务

使用 webpack-dev-server 来启动本地服务,方便开发以及本地调试

执行 npm install --save-dev webpack webpack-dev-server

在 package.json 文件对应的 scripts 处写入命令

package.json

  {
    "scripts": {
+     "dev": "webpack serve",
      "build": "webpack"
    }
  }

执行 npm run dev 即可启动本地服务,访问 localhost:8080 即可,8080 是默认的端口号,可以在配置文件中修改端口号

webpack.config.js

module.exports = {
  // ...
  devServer: {
    compress: true,
    port: 8080
  }
}

生成 HTML 文件

使用 html-webpack-plugin 来生成 HTML 文件

执行 npm install --save-dev html-webpack-plugin

在 webpack.config.js 配置文件中添加

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './index.html'
    })
  ]
}

安装 Vue

执行 npm install --save-dev vue-loader vue-template-compiler

执行 npm install --save vue vue-router

在 webpack.config.js 中配置 vue-loader 用于引入 .vue 类型文件

webpack.config.js

const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: [
          {
            loader: 'vue-loader'
          }
        ]
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin()
  ]
}

新建一个 app.vue 文件作为路由组件的容器

project

  project-name
+ |- app.vue
  |- index.html
  |- index.js
  |- package.json
  |- webpack.config.js

app.vue

<template>
<router-view></router-view>
</template>

<script>
export default {}
</script>

index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

import appView from 'app.vue'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: require('./index.vue').default
    }
  ]
})

new Vue({
  el: '#app',
  router,
  render(h) { return h(appView) }
})

新建一个 index.vue 文件作为首页

project

  project-name
  |- app.vue
  |- index.html
  |- index.js
  |- package.json
+ |- index.vue
  |- webpack.config.js

index.vue

<template>
<div>
  <h1>这是首页</h1>
</div>
</template>

<script>
export default {}
</script>

添加页面

添加一个 about.vue 文件作为关于页

project

  project-name
+ |- about.vue
  |- app.vue
  |- index.html
  |- index.js
  |- package.json
  |- index.vue
  |- webpack.config.js

about.vue

<template>
<div>
  <h1>这是关于页</h1>
</div>
</template>

<script>
export default {}
</script>

配置关于页的路由

index.js

// ...

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: require('./index.vue').default
    },
    {
      path: '/about',
      component: require('./about.vue').default
    },
  ]
})

访问 http://localhost:8080/#/about 即可显示关于页

文件分类

随着页面的增加,vue 文件将会越来越多,放在项目根目录下面并不科学,在当前目录创建一个 src 目录用来放置开发源文件

在 src 目录中创建一个 pages 目录用来放置 vue 页面文件,将 app.vue、index.vue、about.vue 文件移入 pages 目录中,同时修改对应的引用路径

project

  project-name
- |- about.vue
- |- app.vue
  |- index.html
  |- index.js
  |- package.json
- |- index.vue
  |- webpack.config.js
+ |- /src
+   |- /pages
+     |- about.vue
+     |- app.vue
+     |- index.vue

index.js

// ...

import appView from './src/pages/app.vue'

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: require('./src/pages/index.vue').default
    },
    {
      path: '/about',
      component: require('./src/pages/about.vue').default
    },
  ]
})

./src/pages/index.vue 这种长路径写起比较麻烦,在 webpack.config.js 中配置一个 alias 参数

webpack.config.js

module.exports = {
  // ...
  resolve: {
    alias: {
      '@': path.join(__dirname, 'src')
    }
  }
}

上面的页面路径可以再次改写

index.js

// ...

import appView from '@/pages/app.vue'

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: require('@/pages/index.vue').default
    },
    {
      path: '/about',
      component: require('@/pages/about.vue').default
    },
  ]
})

同时,将路由配置单独提取出来,新建一个 routes.js 文件放在 src/js 目录中(js 目录需要新建)

project

  project-name
  |- index.html
  |- index.js
  |- package.json
  |- webpack.config.js
  |- /src
+   |- /js
+     |- routes.js
    |- /pages
      |- about.vue
      |- app.vue
      |- index.vue

routes.js

module.exports = [
  {
    path: '/',
    component: require('@/pages/index.vue').default
  },
  {
    path: '/about',
    component: require('@/pages/about.vue').default
  },
]

index.js

// ...

import routes from '@/js/routes'

const router = new VueRouter({
  routes
})

配置 Babel

由于前面的代码使用了 ES2015 的语法,为了使项目兼容更多浏览器,需要用 Babel 对代码进行转换

执行 npm install --save-dev @babel/core @babel/preset-env babel-loader

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      }
    ]
  }
}

创建一个 .babelrc 文件(不知道怎么创建?可以直接从该项目中复制)

project

  project-name
+ |- .babelrc
  |- index.html
  |- index.js
  |- package.json
  |- webpack.config.js
  ...

.babelrc

{
  "presets": ["@babel/preset-env"]
}

CSS

项目中肯定会用到 CSS,首先新建一个 style.css 样式文件,项目中的样式就可以写在这里面

project

  project-name
  |- .babelrc
  |- index.html
  |- index.js
  |- package.json
+ |- style.css
  |- webpack.config.js
  ...

然后安装 Normalize.css 用于使各种浏览器呈现一致的效果,这只是一种样式初始化方案,是可选的,另外也可以选择 Bootstrap 或者 Bulma 等包含更多样式的样式库来作为开发的基础

执行 npm install --save normalize.css

直接在 index.js 里面引用

index.js

import 'normalize.css'
import './style.css'
// ...

由于这里直接在 js 文件中引用了 css 文件,所以需要 css-loader 来处理

执行 npm install --save-dev css-loader style-loader

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader'
          }
        ]
      }
    ]
  }
}

另外也可以在 vue 文件里面写 CSS

index.vue

<template>
<div>
  <h1>这是首页</h1>
</div>
</template>

<script>
export default {}
</script>

<style>
h1 {
  text-align: center;
}
</style>

两种写样式的方式可以根据具体需求选择使用

提取样式文件

上面引入 css 的方式最终打包之后 CSS 代码都在 js 里面,为了网站的性能需要将 CSS 单独提取出来,使用 mini-css-extract-plugin 插件来提取 CSS

执行 npm install --save-dev mini-css-extract-plugin

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader // 代替 style-loader
          },
          {
            loader: 'css-loader'
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: `[name].css`
    })
  ]
}

处理图片

项目中如果有用到图片需要 file-loader 来处理

执行 npm install --save-dev file-loader

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'file-loader'
      }
    ]
  }
}

准备一张图片 logo.gif 放在 src/images 目录中(images 目录需要新建,这张图片是用来测试的)

project

  project-name
  |- .babelrc
  |- index.html
  |- index.js
  |- package.json
  |- style.css
  |- webpack.config.js
  |- /src
+   |- /images
+     |- logo.gif
    |- /js
      |- routes.js
    |- /pages
      |- about.vue
      |- app.vue
      |- index.vue

index.vue

<template>
<div>
  <h1>这是首页</h1>
  <img src="@/images/logo.gif">
</div>
</template>

<script>
export default {}
</script>

<style>
h1 {
  text-align: center;
}
</style>

执行 npm run build 打包后发现图片已经成功打包进来了,但是图片的名称改变了,如果不希望改变图片名称,可以给 file-loader 配置参数

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'file-loader',
        options: {
          name: 'images/[name].[ext]'
        }
      }
    ]
  }
}

压缩 CSS

使用 cssnano 压缩 CSS,该插件属于 PostCSS 生态系统,所以需要同时安装 postcss-loader

执行 npm install --save-dev cssnano postcss-loader

创建一个 postcss.config.js 文件,这是 PostCSS 的配置文件,相关配置都写在这里面

project

  project-name
  |- .babelrc
  |- index.html
  |- index.js
  |- package.json
+ |- postcss.config.js
  |- style.css
  |- webpack.config.js
  ...

postcss.config.js

module.exports = {
  plugins: {
    'cssnano': {
      safe: true
    }
  }
}

webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          {
            loader: 'css-loader'
          },
          {
            loader: 'postcss-loader'
          }
        ]
      }
    ]
  }
}

CSS 预处理

这里使用 postcss-preset-env 来预处理 CSS(也可以选择使用 Sass 或者 Less 等)

执行 npm install --save-dev postcss-preset-env

该插件也属于 PostCSS 生态系统,直接在 postcss.config.js 里增加配置即可

postcss.config.js

  module.exports = {
    plugins: {
+     'postcss-preset-env': {},
      'cssnano': {
+       autoprefixer: false, // 这里两个插件都包含了 autoprefixer,只执行其中一个就行
        safe: true
      }
    }
  }

HTTP 请求

使用 Axios 发送 HTTP 请求,Axios 基于 Promise,所以同时安装 es6-promise polyfill

执行 npm install --save axios es6-promise

index.js

+ import 'es6-promise/auto'
+ import axios from 'axios'

  // ...

在项目中发送一个请求

index.js

  import 'es6-promise/auto'
  import axios from 'axios'

+ axios.post('/login')

  // ...

运行后这个请求明显会返回一个 404,那么如何让它返回有效的数据呢,在 webpack.config.js 里配置 devServer 参数

webpack.config.js

  module.exports = {
    // ...
    devServer: {
+     before(app, server) {
+       app.post('/login', (req, res) => {
+         res.json({success: true})
+       })
+     },
      compress: true,
      port: 8080
    }
  }

重新启动后,就可以看到请求 /login 地址返回了数据 {"success": true},这样就可以在本地调试接口了

当然,所有接口都这样写未免麻烦,可以用 proxy 参数将请求接口代理到其它地址去

webpack.config.js

  module.exports = {
    // ...
    devServer: {
      before(app, server) {
        app.post('/login', (req, res) => {
          res.json({success: true})
        })
      },
+     proxy: {
+       '/api': {
+         target: 'http://localhost:3000'
+       }
+     },
      compress: true,
      port: 8080
    }
  }

这时,例如请求 /api/posts 实际上会被代理到 http://localhost:3000/api/posts

打包

配置 mode 参数

webpack.config.js

module.exports = {
  mode: 'production'
  // ...
}

productiondevelopment 两种 mode 参数很明显,production 用于发布,development 用于开发,具体有什么区别,看这里 Click here

执行 npm run build 即可打包,打包后生成的文件都在 dist 目录中

更多

posted @ 2019-09-26 14:51  by.Genesis  阅读(1257)  评论(0编辑  收藏  举报