说明

这是我根据慕课网上的一个课程 Vue+Webpack打造todo应用 过程一步步搭下来的框架,去掉了业务相关的逻辑。

项目最终的效果包括了引入vue框架;使用CSS预处理器;使用babel;引用图片等静态资源;区分开发环境与生成环境,并做相应优化等。基本接近真正做项目时候的配置。

但是!! 毕竟是我个人根据练习课程搭的框架,跟真实工作可能有区别,请谨慎直接用于工作环境!!!

项目的最终成果看这里:https://gitee.com/Dandelion_/vue-webpack-scaffold

Tips:项目里面的 commit 对应文章的每一小节,所以大家善用 git checkout <commit> 命令可以很方便地切换到某个 commit 看当前版本的文件变化哦。当然直接看项目的 commit 列表也行啦。


0. 前言

首先不得不说 vue-cli + vue-webpack 模版真的很方便,vue init webpack my-vue-project 就搭好框架了,而且开发环境生产环境都有了。npm run dev 启动开发环境,npm run build 发布生产环境。几个命令全部搞定了。但是模版有时候可能不够灵活,或者我们想修改其中一些东西,面对这些需求的时候,理解怎么搭建起这个 vue + webpack 的环境还是很有用的。那最快捷的方式,当然是自己从头开始搭一遍啦。心动不如行动,走~~


1. 新建项目

因为不用 vue-cli 和 vue 模版,所以一开始我们就建个空文件夹。

mkdir my-vue-project
cd my-vue-project
npm init # 初始化项目。这时候会问你一些问题,比如项目名称、作者之类的,照着提示回答问题就好

2. 安装基本的 npm 包

首先肯定要安装 vuewebpack。然后 webpack 4.x已经把 cli 单独拎出来了,所以还要安装 webpack-cli;然后因为 webpack 本身其实直接能处理的只有 js 资源,是通过各种 loader 让其他资源可以被 webpack 打包处理的。那么现在我们要用 vue 写单文件组件(就是 .vue 文件),所以就还要安装 vue-loader

npm install vue vue-loader webpack webpack-cli --save-dev # --save-dev表示这些只是开发环境所需的依赖

3. 添加项目各种入口文件

入口文件都是很普遍的那种,比如根目录下的 index.htmlsrc 文件夹下的 main.jsapp.vue 等等,我就不一一解释了。

添加入口文件后的项目目录如下:

.
├── dist/
| ├── ...
├── src/
| ├── main.js
| ├── app.vue
├── node_modules/
| ├── ...
├── index.html
├── package.json

更详细的项目结构和具体文件内容可以看 这个commit

4. 添加 webpack 配置文件

在项目根目录下添加 webpack.config.js 文件。内容如下:

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = {
entry: path.join(__dirname, 'src/main.js'), // 项目总入口js文件
// 输出文件
output: {
path: path.join(__dirname, 'dist'), // 所有的文件都输出到dist/目录下
filename: 'bundle.js'
},
module: {
rules: [{
// 使用vue-loader解析.vue文件
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
// 要加上style-loader才能正确解析.vue文件里的<style>标签内容
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new VueLoaderPlugin() // 最新版的vue-loader需要配置插件
]
};

5. 添加构建脚本

package.json 文件的 scripts 属性里添加 build 脚本

   "scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "build": "webpack --config webpack.config.js"
},

因为我们添加了一些引用,比如 style-loadercss-loader 等,所以也要安装相应的包。

npm i style-loader css-loader vue-template-compiler --save-dev

安装好依赖后运行 npm run build 来构建项目。

构建成功后在项目根目录启动一个静态资源服务器,然后浏览就可以看到以下页面了。

6. 添加图片、CSS 预处理器等 loader

图片 loader 用的是 url-loader,它依赖于 file-loader,比 file-loader 多了一个可以比小于一定大小的图片直接转化成 base64 的形式插入到 html 页面,可以减少网络请求。

CSS 预处理器 我选的是 SASS

安装依赖:

npm i file-loader url-loader node-sass sass-loader --save-dev

修改 webpack.config.js

		module.exports =
{
test: /\.css$/,
// 要加上style-loader才能正确解析.vue文件里的<style>标签内容
use: ['style-loader', 'css-loader']
+ },
+ {
+ test: /\.scss$/,
+ use: [
+ // 处理顺序是从sass-loader到style-loader
+ 'style-loader',
+ 'css-loader',
+ 'sass-loader'
+ ]
+ },
+ {
+ test: /\.(gif|jpg|jpeg|png|svg)$/i,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ // 当文件大小小于limit byte时会把图片转换为base64编码的dataurl,否则返回普通的图片
+ limit: 8192,
+ name: 'dist/assest/images/[name]-[hash:5].[ext]' // 图片文件名称加上内容哈希
+ }
+ }]
}
]
},
...

测试一下:

添加 src/assets/styles/global.scss 文件

+.play {
+ background-image: url('../images/play.png');
+ background-repeat: no-repeat;
+ width: 64px;
+ height: 64px;
+ padding: 0;
+ border: 0;
+ background-color: transparent;
+ margin: 0;
+ cursor: pointer;
+}

src/main.js 引用 global.scss

 import Vue from 'vue'; // 从node_modules引入vue类库
import App from './app.vue'; // ES6 语法,相当于 import { default as App } from './app.vue'。因为app.vue用过的是export default {...},所以可以这样写 +import './assets/styles/global.scss';
+
new Vue({
el: '#app',
components: {

运行 npm run build,刷新页面,能看到如下效果:

button 的背景图是 1.97kb,小于 8192byte,可以看到图片已经被转换成 base64 的内容了。

7. 添加 postcss-loader + autoprefixer,自动添加 css 浏览器前缀

安装依赖:

npm i postcss-loader autoprefixer --save-dev

新增 postcss 配置文件 postcss.config.js

const autoprefixer = require('autoprefixer');

module.exports = {
plugins: [
autoprefixer({
browsers: ['last 5 versions']
})
]
};

修改 webpack.config.js

	...
module: {
rules: [
...
{
test: /\.css$/,
use: [
// 要加上style-loader才能正确解析.vue文件里的<style>标签内容
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [
// 处理顺序是从sass-loader到style-loader
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'sass-loader'
]
},
...

测试一下:

修改 index.html

     <h1>一个用 vue + webpack 搭建的脚手架框架</h1>
<div id="app"></div>
<button class="play"></button>
+ <div class="flex">
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ </div>
<script src="/dist/bundle.js"></script>
</body>

修改 global.scss


+.flex {
+ display: flex;
+ border: solid #000 2px;
+ width: 300px;
+ height: 100px;
+ .flex-item {
+ flex: 1;
+ background-color: #1296db;
+ border: solid #fff 1px;
+ }
}

运行 npm run build,刷新页面,能看到如下效果:



可以看到 flex 已经加上了浏览器前缀了。

8. 添加 babel-loader,转译 es6 代码为 es5 代码

添加.babelrc文件

{
"presets": [
"env"
],
"plugins": [
"transform-vue-jsx"
]
}

安装依赖

npm i babel-loader@7 babel-core babel-preset-env --save-dev

修改 webpack.config.jsmodule.rules 再加一条:

{
test: /\.js$/,
exclude: /(node_modules|bower_components)/, // 不处理这两个文件夹里的内容
loader: 'babel-loader'
}

测试一下:

修改 main.js,加上以下代码

// 测试babel-loader
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
} sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
}

在浏览器查看输出,如下图:

如果注释掉 webpack.config.jsbabel-loader 这条规则,则编译之后如下:

可以看到 babel-loader 已经起作用了。

9. 添加 html-webpack-plugin,自动生成 index.html 的内容

添加 HtmlWebpackPlugin,在 dist 文件夹也生成 index.html 页面,而且会自动加上对项目入口 js 文件的引用,也就是说我们自己写的 index.html 可以不用再手动指定 js 文件了,它会把 webpack 配置里的 entry 当中指定的 js 都插入到生成的 index.html 中,而且当输出的文件添加上 hash 值时也可以自动跟踪。

安装依赖

npm i html-webpack-plugin --save-dev

修改 webpack.config.js

 const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {
entry: path.join(__dirname, 'src/main.js'), // 项目总入口js文件
// 输出文件
output: {
path: path.join(__dirname, 'dist'),
- filename: 'bundle.js'
+ filename: 'bundle-[hash].js' // 输出文件的名称加上hash值
},
module: {
rules: [{
...
]
},
plugins: [
- new VueLoaderPlugin() // 最新版的vue-loader需要配置插件
+ new VueLoaderPlugin(), // 最新版的vue-loader需要配置插件
+ new HtmlWebpackPlugin({
+ filename: 'index.html', // 生成的文件名称
+ template: 'index.html', // 指定用index.html做模版
+ inject: 'body' // 指定插入的<script>标签在body底部
+ })
]
};

修改 index.html,把原来引用 bundle.js<script> 去掉。

然后我们 build 一下,看 dist 文件夹的输出。

可以看到 dist 文件夹下多了 index.html 文件,而且文件内容自动加上了编译出来的 bundle.js 文件的引用。

10. 添加 clean-webpack-plugin,每次 build 之前可以自动先清除输出文件夹

如果我们对输出的文件名称加上了哈希值的话,每次修改之后的哈希值都不一样,就是每次都生成了一个新的文件,那旧的那些其实就是多余的文件了(上面那张图的 dist 文件夹可以看出来)。因此我们可以用 clean-webpack-plugin 这个插件,在每次 build 之前先清除输出文件夹。

安装依赖

npm i clean-webpack-plugin --save-dev

修改 webpack.config.jsplugins 数组添加一项

 const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+const CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports = {
...
plugins: [
new VueLoaderPlugin(), // 最新版的vue-loader需要配置插件
new HtmlWebpackPlugin({
filename: 'index.html', // 生成的文件名称
template: 'index.html', // 指定用index.html做模版
inject: 'body' // 指定插入的<script>标签在body底部
}),
+ new CleanWebpackPlugin(['dist'])
]
};

11. 添加 webpack-dev-server,配置更友好的开发环境

webpack-dev-server 可以在本地启动一个服务器,而且当有任何文件修改的时候会自动重新打包,并且刷新浏览器页面。此外 devServer 还有很多其他配置项,让我们可以更方便的开发。

安装依赖

npm i webpack-dev-server cross-env --save-dev

用上 cross-env 是因为我们接下来要修改 package.json 里的 scripts,而不同的平台写scripts 的方式不一样。

修改 package.json 里的 scripts

    ...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "build": "webpack --config webpack.config.js"
+ "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
+ "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
},
....

修改 webpack.config.js,这次改得比较多,可以看这里的 commit detail

配置好以后我们可以运行 npm run dev 命令启动一个服务器了

12. 配置生产环境 css 单独分离打包,方便浏览器缓存

安装依赖

npm i mini-css-extract-plugin --save-dev

修改 webpack.config.js,改动的地方看这个 commit detail

13. 单独打包类库文件

因为类库文件是不用像业务代码一样经常更新的,单独打包可以让它们在浏览器里缓存,提高加载速度。

修改 webpack.config.js,改动的地方看这个 commit detail


到这里基本的配置都完成了,一个基础的 vue 项目框架就搭好啦,接下来我们只需要专注于添加自己项目的业务逻辑页面和代码就好了。愉快地敲(xie)代(bug)码去吧~~

PS: 这个是目前为止用到的配置,其实真实生成环境要做的优化应该还有不少,比如图片压缩处理等等,大家要根据自己的项目需要来扩展哦。如果以后有用到其他的插件比较通用的应该会更新这篇文章。嗯,也就是不定期无规律看心情更新2333【逃。。】


本文首发于我的个人网站【https://dandelion-drq.github.io】,欢迎访问。

不使用 vue-cli 与 vue 模版,使用 Vue2.x + webpack4.x 从零开始一步步搭建项目框架的更多相关文章

  1. [Vue CLI 3] vue inspect 的源码设计实现

    首先,请记住: 它在新版本的脚手架项目里面非常重要 它有什么用呢? inspect internal webpack config 能快速地在控制台看到对应生成的 webpack 配置对象. 首先它是 ...

  2. Vue CLI及其vue.config.js(一)

    有时候我们为了快速搭建一个vue的完整系统,经常会用到vue-cli,vue-cli用起来很方便而且命令简单容易上手,但缺点是在构建的时候我感觉有一些慢,因为CLI 服务 (@vue/cli-serv ...

  3. 使用Vue CLI构建Vue项目

    第一步:首先在控制台输入vue --version,如果出现版本号则进入第三步:否则进入第二步: 第二步:输入npm install cnpm -g --registry=https://regist ...

  4. [Vue 牛刀小试]:第十六章 - 针对传统后端开发人员的前端项目框架搭建

    一.前言 在之前学习 Vue 基础知识点的文章中,我们还是采用传统的方式,通过在 html 页面上引用 vue.js 这个文件,从而将 Vue 引入到我们的项目开发中.伴随着 Node.js 的出现, ...

  5. [Vue CLI 3] @vue/cli-plugin-eslint 源码分析

    熟悉 eslint-loader 的同学一般如下配置: 设置一下几项: test : A condition that must be met(一般是处理对应文件的正则) exclude : A co ...

  6. Vue CLI 3.x 简单体验

    文档 中文文档 补充于02月10日 vue脚手架的3.x版本已经在开发中,现在还处于alpha版本.我们来看看有哪些变化. 使用 npm install -g @vue/cli 命名方式已经改为npm ...

  7. [转]Vue CLI 3搭建vue+vuex 最全分析

    原文地址:https://my.oschina.net/wangnian/blog/2051369 一.介绍 Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统.有三个组件: CLI:@ ...

  8. vue cli脚手架使用

    1.安装nodejs,npm https://www.cnblogs.com/xidianzxm/p/12036880.html 2.安装vue cli sudo npm install -g @vu ...

  9. ubuntu下安装vue/cli提示No command 'vue' found

    通过官方指令 npm install -g @vue/cli 安装vue脚手架提示: No command 'vue' found, did you mean: Command 'vpe' from ...

随机推荐

  1. 你的网站升级https了吗

    升级 HTTPS,价值何在? HTTPS 实质上是一种面向安全信息通信的协议.从最终的数据解析的角度上看,HTTPS 与 HTTP 没有本质上的区别.对于接收端而言,SSL/TSL 将接收的数据包解密 ...

  2. Java设计模式学习记录-适配器模式

    前言 之前已经将五个创建型设计模式介绍完了,从这一篇开始介绍结构型设计模式,适配器模式就是结构型模式的一种,适配器要实现的效果是把“源”过渡到“目标”. 适配器模式 在开发过程中,使用一个已经存在的类 ...

  3. .36-浅析webpack源码之Parser类

    眼看webpack4都出了,我还在撸3的源码,真的是捉急啊…… 不过现在只是beta版本,等出稳定版本后跑跑4的源码去. 之前漏了一个东西没有讲,如下: asyncLib.parallel([/**/ ...

  4. oracle中scott/tiger、sys、SYSDBA、system都是什么用

    scott 是个演示用户,是让你学习ORACLE用的 SYSDBA 不是用户,可以认为是个权限,超级权限详细点说吧            超级用户分两种 SYSDBA和SYSOPTSYSOPT 后面3 ...

  5. Java基础——JSP(二)

    一.JSP隐式对象概述 为了简化jsp表达式和脚本片断代码的编写,JSP一共提供了9个预先定义的变量,这些变量也称为隐式对象或内置对象. 在 jsp生成的Servlet源码中,有如下声明: publi ...

  6. Elasticsearch Query DSL 整理总结(二)—— 要搞懂 Match Query,看这篇就够了

    目录 引言 构建示例 match operator 参数 analyzer lenient 参数 Fuzziness fuzzniess 参数 什么是模糊搜索? Levenshtein Edit Di ...

  7. 两车追及或相遇问题(hdu1275)数学题

    两车追及或相遇问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  8. ActivityManagerService原理&源码

    https://www.kancloud.cn/alex_wsc/android-deep2/413386 http://wiki.jikexueyuan.com/project/deep-andro ...

  9. java 非阻塞算法实现基础:unsafe类介绍

    一.为什么要有Unsfae.我们为什么要了解这个类 1. java通常的代码无法直接使用操作底层的硬件,为了使java具备该能力,增加了Unsafe类 2.java的并发包中底层大量的使用这个类的功能 ...

  10. JS中判断数据类型的几种方法

    1⃣️首先我们来了解一下js中的数据类型 1.基本数据类型:Undefined.Null.Boolean.Number.String(值类型) 2.复杂数据类型:Object(引用类型) (值类型和引 ...