从零搭建 vue2 vue-router3 webpack4 工程
和《从零搭建 vue2 vue-router2 webpack3 工程》一样,以新手视角,详细介绍各个步骤内容,不深入讲步骤涉及的原理,主要介绍如何操作。
文中示例工程地址:https://github.com/qinshenxue/vue2-vue-router2-webpack4。
初始化工程
新建工程目录 vue2-vue-router3-webpack4,在目录下执行npm init -y
来创建一个 package.json,在 package.json 中先添加以下必要模块:
{
"name": "vue2-vue-router3-webpack4",
"version": "1.0.0",
"devDependencies": {
"vue": "^2.6.10",
"vue-loader": "^15.7.0",
"vue-router": "^3.0.6",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.5.1"
}
}
Webpack 4 开始,命令行工具(CLI)需要单独安装。
新建目录结构如下,新增的目录及文件先空着,后面的步骤会说明添加什么内容。
vue2-vue-router3-webpack4
|-- package.json
|-- index.html // 访问首页
|-- webpack.config.js // Webpack 配置文件
|-- src
|-- views // Vue 页面目录
|-- main.js // 入口起点
|-- router.js // vue-router 配置
|-- app.vue // Vue 根组件
配置 Webpack
Webpack 默认读取 webpack.config.js,其中 entry 是必须配置的,构建时,output.filename
是必需的。
module.exports = {
mode: "development",
entry: './src/main.js',
output: {
path: __dirname + '/dist',
publicPath: '/static/',
filename: 'build.js'
}
}
Webpack 4 增加了 mode 配置项,支持配置
"production" | "development" | "none"
三个可选配置,默认为"production"
。
mode 的作用可以简单概括为把各个环境常用的配置缩减为一个配置。
配置为 development 背后实际上是包含了如下配置。图片截自官网。
配置为 production 背后实际上是包含了如下配置。
webpack-dev-server 不需要配置文件,直接使用其 CLI 提供的命令即可。
"scripts": {
"dev": "webpack-dev-server --hot --open"
}
验证配置
在 index.html 中添加测试代码,引入打包后的 JavaScript 文件。
<body>
Hello, Webpack 4.
<br>
<script src="/static/build.js"></script>
</body>
在 main.js 中添加测试代码。
// main.js
document.write('来自 main.js 的问候!')
执行下面的命令来安装依赖模块并启动本地服务器。
# 安装依赖模块
npm install
# 启动本地服务器
npm run dev
启动后浏览器会自动打开http://localhost:8080
,如果控制台没有报错,页面正确显示 main.js 和 index.html 的内容,改动 main.js 后浏览器会自动刷新,则表示配置没问题。
Vue
新建页面
在 views 目录下新建 index.vue。
<template>
<div>
这是{{page}}页面
</div>
</template>
<script>
export default {
data() {
return {
page: 'index'
}
}
}
</script>
配置路由
将 vue-router 实例化传入的参数提取到 router.js 作为路由配置文件。
import index from './views/index.vue'
export default {
routes: [
{
path: '/index',
component: index
}
]
}
修改首页
在 index.html 添加 Vue 根实例的挂载元素。
<body>
<div id="app"></div>
<script src="/static/build.js"></script>
</body>
修改入口
在 main.js 完成路由配置、初始化 Vue 实例。
import Vue from "vue"
import VueRouter from "vue-router"
import App from "./app.vue"
import routerConfig from "./router"
Vue.use(VueRouter)
const router = new VueRouter(routerConfig)
new Vue({
el: "#app",
router: router,
render: h => h(App)
})
在根组件 app.vue 中添加路由链接、路由视图组件。
<template>
<div>
<div>
<router-link to="/index">Home</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
配置 loader
配置 .vue 文件对应的 loader。
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
mode: "development",
entry: './src/main.js',
output: {
path: __dirname + '/dist',
publicPath: '/static/',
filename: 'build.js'
},
module: {
rules: [{
test: /\.vue$/,
use: ["vue-loader"]
}]
},
plugins: [
new VueLoaderPlugin()
]
}
vue-loader 从 v15.0.0 开始,配置需要引入
vue-loader/lib/plugin
,并在 plugins 中初始化。详细请参考官方文档 https://vue-loader.vuejs.org/zh/guide/#vue-cli。
上面完成了访问一个页面所需要的步骤,接下来可以启动本地服务器(npm run dev
)来测试能否正常访问/index。
支持 CSS
直接在 .vue 文件中使用 CSS 会提示You may need an appropriate loader to handle this file type.
,CSS 对应的 loader 为css-loader
。
npm install css-loader -D
vue-loader v15.0.0 之前不需要配置 loader 就可以在 vue 文件中使用 CSS,需要用 import 或 require CSS 文件时才需要配置 loader,而 v15.0.0 之后均需要自己配置 loader 才不会报错。
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"]
}
import './assets/css/style.css'
vue-style-loader 是 vue-loader 的 dependencies,因此不需要再自己安装,css-loader 是 vue-loader 的 peerDependencies,需要自己安装。
支持 CSS 预处理语言
根据需要安装预处理语言模块及对应的 loader。
# less
npm install less less-loader -D
# sass
npm install node-sass sass-loader -D
# stylus
npm install stylus stylus-loader -D
node-sass 安装慢的解决办法:
- 使用淘宝镜像:
npm set disturl https://npm.taobao.org/dist
- 也可以单独设置 node-sass 镜像:
npm set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass
各种预处理语言的 loader 配置。
// less
{
test: /\.less$/,
use: ["vue-style-loader", "css-loader", "less-loader"]
}
// sass
{
test: /\.s[ac]ss$/,
use: ["vue-style-loader", "css-loader", "sass-loader"]
}
// stylus
{
test: /\.styl$/,
use: ["vue-style-loader", "css-loader", "stylus-loader"]
}
使用示例。
<style lang="less">
.view{
color:red;
}
</style>
<style lang="sass">
.view{
border-bottom:1px solid #ddd;
}
</style>
<style lang="styl">
.view
margin-top:20px;
</style>
支持图片及图标字体
安装图片及图标字体依赖的 loader。
npm install url-loader file-loader -D
配置图片及图标字体对应的 loader。
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]' // 将图片都放入 images 文件夹下,[hash:7]防缓存
}
}]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]'
}]
}
url-loader 的配置limit:10000
即图片文件小于 10000/1024 ≈ 9.7 KB 会被转换成 base64。如果不配置 limit 或者 limit 配置为 0,那么所有图片都会被转成 base64,如果不想被转换,可以把 limit 配置得足够小,比如 1,源码中将 limit 转成了整数,因此小数无效。
构建
使用 Webpack CLI 提供的命令构建。点击查看 Webpack 命令参数
"build": "webpack --progress"
执行npm run build
开始构建,完成后,可以看到工程目录下多了 dist 目录,里面包含了打包后的 JavaScript 文件、图片、图标字体文件,但是打包后的 JavaScript 文件没有被压缩,里面还包含了 CSS 代码,语法也没有被转换成 ES5,这些工作就需要使用 Webpack 插件来完成。
使用 Webpack 插件
Babel
Babel 7 正式版已经发布,较 Babel 6 变化如下:
- 不再支持不在维护中的 Node 版本:0.10、0.12、4、5;
- 使用 @babel 命名空间,因此 babel-core 就变成了 @babel/core;
- 移除(并停止发布)任何年度预设(preset-es2015 等),@babel/preset-env 取代了对这些内容的需求 ;
- 移除“Stage” 预设(@babel/preset-stage-0 等),同时移除了 @babel/polyfill 中的提议;
- 重命名了某些包:任何 TC39 提议插件现在都是 -proposal 而不是 -transform,所以 @babel/plugin-transform-class-properties 变成了 @babel/plugin-proposal-class-properties;
- 针对某些面向用户的包(例如 babel-loader、@babel/cli 等)在 @babel/core 中引入 peerDependency。
安装 Babel。
npm install babel-loader @babel/core @babel/cli @babel/preset-env -D
增加 Babel 配置文件 babel.config.js。
const presets = [
["@babel/env", {
targets: {
ie: "9"
},
modules: false
}]
]
module.exports = {
presets
}
配置 babel-loader。
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
压缩
上面提到过, Webpack 4 新增的 mode 配置项配置为'production'
时,背后包含了压缩的配置optimization.minimize : true
,因此不用再额外配置。
提取 CSS
extract-text-webpack-plugin 不支持 Webpack 4,提取 CSS 改用 mini-css-extract-plugin
npm i mini-css-extract-plugin -D
调整 Webpack 配置如下。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
//...
module: {
rules: [{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
}, {
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"]
}, {
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}, {
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"]
}
//...
]
},
plugins: [
// ...
new MiniCssExtractPlugin({
filename: 'css/style.css'
})
]
}
vue-loader 不需要单独配置就可以提取 vue 文件中的 CSS。在 index.html 中引入 CSS 文件即可看到效果。
CSS 压缩及优化
安装 postcss-loader 及 PostCSS 插件。
npm install postcss-loader autoprefixer cssnano -D
loader 配置调整如下。
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader']
}, {
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "less-loader"]
}, {
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "sass-loader"]
}, {
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "stylus-loader"]
}
postcss-loader 要放在 css-loader 后,CSS 预处理语言的 loader 之前。
新增 postcss-loader 需要配置文件 postcss.config.js,引入插件。
module.exports = {
plugins: [
require('autoprefixer'),
require('cssnano')
]
}
autoprefixer 配置 browsers 需要新增 .browserslistrc 来配置,比如要兼容安卓 4.0 以上。
android > 4
PostCSS 插件分类搜索网站:http://postcss.parts/
生成首页
手动引入打包后的 JavaScript 和 CSS 比较麻烦,使用 html-webpack-plugin 插件生成的页面自动引入了打包后的资源。
npm install html-webpack-plugin -D
初始化插件。
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.tpl.html'
})
]
index.tpl.html
<html>
<head>
...
</head>
<body>
<div id="app"></div>
</body>
</html>
分离 Webpack 配置
将开发和生产配置文件分离,方便增加各个环境下的个性配置。Webpack 官方文档中也详细阐述了如何为多环境增加配置文件,基本思路如下。
- 编写一个基本配置文件(webpack.base.config.js)
- 使用 webpack-merge 合并这个基础配置和针对环境的特定的配置(webpack.dev.config.js,webpack.prod.config.js)
webpack.base.config.js 内容如下。
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: './src/main.js',
output: {
filename: 'js/[name].js'
},
module: {
rules: [{
test: /\.vue$/,
use: ["vue-loader"]
}, {
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]' // 将图片都放入 images 文件夹下,[hash:7]防缓存
}
}]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]' // 将字体放入 fonts 文件夹下
}
}]
}
]
},
plugins: [
new VueLoaderPlugin()
]
}
开发环境一般不配置提取 CSS,而生产环境需要配置,因此上面的基础配置不包含 CSS loader。path 和 publicPath 在开发和生产环境下一般不同,因此也不包含在基础配置中。
开发配置文件(webpack.dev.config.js)内容如下内容如下。
const merge = require("webpack-merge")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const baseWebpackConfig = require("./webpack.base.config")
module.exports = merge(baseWebpackConfig, {
mode: 'development',
output: {
publicPath: "/"
},
module: {
rules: [{
test: /\.css$/,
use: ["vue-style-loader", "css-loader", 'postcss-loader']
}, {
test: /\.less$/,
use: ["vue-style-loader", "css-loader", 'postcss-loader', "less-loader"]
}, {
test: /\.s[ac]ss$/,
use: ["vue-style-loader", "css-loader", 'postcss-loader', "sass-loader"]
}, {
test: /\.styl$/,
use: ["vue-style-loader", "css-loader", 'postcss-loader', "stylus-loader"]
}]
},
plugins: [
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.tpl.html"
})
]
})
生产配置文件(webpack.prod.config.js)内容如下。
const merge = require("webpack-merge")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const baseWebpackConfig = require("./webpack.base.config")
const path = require('path')
module.exports = merge(baseWebpackConfig, {
mode: 'production',
output: {
path: path.resolve(__dirname, '../dist')
publicPath: "/static/"
},
module: {
rules: [{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader']
}, {
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "less-loader"]
}, {
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "sass-loader"]
}, {
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'postcss-loader', "stylus-loader"]
}]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/style.css'
}),
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.tpl.html"
})
]
})
对应在 package.json 中添加开发和生产构建的命令如下。
"scripts": {
"dev": "webpack-dev-server --progress --hot --open --config build/webpack.dev.config.js",
"build": "webpack --progress --config build/webpack.prod.config.js",
}
更多 Webpack 插件使用请参考[《Webpack 插件配置》](https://www.qinshenxue.com/article/2019-06-05-16-55-58.html)