使用 webpack 搭建 vue 开发环境(二)
# 使用 webpack 搭建 vue 开发环境(二)
接着上一回,第二篇文章开始更进一步的配置
老规矩,基于 v0.0.1 (opens new window) 的代码继续开发,这次配置结束后的代码将会划分为 v0.0.2 (opens new window)
# 使用 less 完善开发体验
安装使用 css 预处理器-less
npm install --save-dev less less-loader
修改配置,因为 test
是可以接收正则表达式的,那么对于 css
和less
的匹配,我们可以这样写:test: /\.(less|css)$/,
- webpack.base.js
修改原先的 test:/\.css$/
的模块
module.exports = {
// ...
module: {
rules: [
{
test: /\.(less|css)$/,
use: ['vue-style-loader', { loader: 'css-loader', options: { esModule: false } }, 'less-loader']
}
]
}
// ...
}
2
3
4
5
6
7
8
9
10
11
12
配置完成后,回到App.vue
。我们在 style 标签上补上 lang="less"
。并且根据 less 语法写一写
- App.vue
<style lang="less">
.text-red {
color: #000;
}
.avatar {
width: 100px;
height: 100px;
&.bg-avatar {
background-image: url('./assets/image/avatar.jpg');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
也可以新建一个 /src/assets/css/common.less
文件,试下 @import
引入的功能
- /src/assets/css/common.less
body {
background-color: #909090;
}
2
3
- App.vue
<style lang="less">
@import './assets/css/common.less';
.text-red {
color: #000;
}
.avatar {
width: 100px;
height: 100px;
&.bg-avatar {
background-image: url('./assets/image/avatar.jpg');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
可以看到都生效了,因为之前的 url-loader
。所以我们在引入文件的时候也是顺顺利利的~
# 配置 css 前缀自动补全
各大浏览器有不同的前缀。自己一个个敲实在是太痛苦了,你能想象到 border-raidus 也会有兼容前缀吗(虽然现在是个浏览器都支持)
要想打包自动加前缀,就要用到 postcss-loader
,和autoprefixer
npm i autoprefixer postcss-loader -D
配置之前,先说几个踩坑的地方,如果配置了 postcss-loader 和 autoprefixer 无效,可以留意下:
配置 Autoprefixer 之前,需要先添加
Browserslist
。可以在根目录加一个.browserslistrc
文件,也可以在package.json
文件中添加:browserslist
。不过一定要加,不然 autoprefixer 不生效其次,必须在根目录创建一个
postcss.config.js
后面会说到autoprefixer 版本处理
webpack.base.js
根据 loader 从右往左的执行顺序
,我们把 postcss-loader
安排在倒数第二位。
module.exports = {
// ...
module: {
rules: [
{
test: /\.(less|css)$/,
use: [
'vue-style-loader',
{ loader: 'css-loader', options: { esModule: false } },
'postcss-loader',
'less-loader'
]
}
]
}
// ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- package.json 我就不多加文件了,直接在 package.json 完成这段配置
{
"browserslist": ["last 2 version", "> 1%", "iOS >= 7", "Android > 4.1", "Firefox > 20"]
}
2
3
- 根目录添加文件 postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}
2
3
为什么需要单独创建
postcss.config.js
,不能写 webpack 配置里面吗?
经过测试,postcss.config.js
存在的目的是因为 webpack 中的 postcss-loader
已经不支持写 plugins
了。所以需要额外的文件进行配置。
configuration has an unknown property 'rules'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, externals?, infrastrdule?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, resolve?, resolveLoader?, serve?, stats?, target?, watch?, watchOptions? }
2
添加需要加前缀的 css 测试下,最简单的就是 display:flex;
。看下效果
为啥呢,因为自动安装的 autoprefixer
版本太高了,我装的是 "autoprefixer": "^10.0.0"
具体可以看下这个 issues (opens new window)
接下来对 autoprefixer
一个降级处理
npm uninstall autoprefixer
npm install autoprefixer@9.8.6 -D
2
3
最后运行也是自动不全了前缀
# 配置 css 样式分离
重点:在开始使用 css 样式和 JS 分离之前,需要一定非常的清楚 publicPath 中 / 和 ./ 的区别!! 如果不了解 publicPath 的作用,可以先看这部分:webpack/vue-cli 中的 publicPath 区别 (opens new window)
搞了那么久,css 的前缀总算是 OK 了,那打包看下效果如何
不打包都没发现,原来 css 都混杂在了 JS 里面,这也意味着原来就很大的 JS 文件,现在更加是雪上加霜,万一页面样式足够复杂,那真是不敢相信
接下来就用到 mini-css-extract-plugin
配置 css 分离和压缩
npm i mini-css-extract-plugin -D
- webpack.base.js
还是改 css 的模块,这次把
vue-style-loader
去掉了 而且 css 输出文件夹配置了非根目录的情况,需要配置publicPath
。根据之前说的 webpack/vue-cli 中的 publicPath 区别 (opens new window) 我就在开发环境下用/
。在生产环境中用../
。MiniCssExtractPlugin.loader
也单独配置 publicPath 为../
。不知道为啥的记得看之前的链接~
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
output: {
filename: '[name].[contenthash].js',
publicPath: './', // base.js 中的这个配置其实会被后面覆盖掉,所以写哪个都没关系
path: path.resolve(ROOT_PATH, 'dist')
},
module: {
rules: [
// ...
{
test: /\.(less|css)$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../' // 注意添加了输出路径
}
},
{ loader: 'css-loader', options: { esModule: false } },
'postcss-loader',
'less-loader'
]
}
]
},
plugins: [
// ...
new MiniCssExtractPlugin({
// css的分离到了单独的 css 目录下,并且哈希值继续使用 contenthash
filename: 'css/[name].[contenthash:4].css'
})
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- webpack.dev.js
const baseConfig = require('./webpack.base')
const { merge } = require('webpack-merge')
const path = require('path')
const ROOT_PATH = path.resolve(__dirname, '../')
module.exports = merge(baseConfig, {
mode: 'development',
output: {
filename: '[name].[contenthash].js',
publicPath: '/', // dev 环境下记得使用 / 不然会有其他问题
path: path.resolve(ROOT_PATH, 'dist')
}
})
2
3
4
5
6
7
8
9
10
11
12
13
- webpack.prod.js
const baseConfig = require('./webpack.base')
const { merge } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const path = require('path')
const ROOT_PATH = path.resolve(__dirname, '../')
module.exports = merge(baseConfig, {
mode: 'production',
output: {
filename: '[name].[contenthash].js',
publicPath: './', // prod 的配置和dev目前是差不多的,不过 publicPath 换成了 './'
path: path.resolve(ROOT_PATH, 'dist')
},
// 而且还多了一个打包清空dist的插件
plugins: [new CleanWebpackPlugin()]
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
运行起来看下效果,css 中的图片前缀已经补全了 ../
,看来已经生效了
最后还是非常强调 对 publicPath 配置的理解,自己动手写 webpack 好处就是自己清楚每个工作的流程嘛!
# 使用babel
把 ES6 转 ES5
现在 vue 环境也有了,less 也装上了(saas 大同小异,有空在补一个插件配置把),然后 css 自动补全也没问题,文件分离的坑也踩过了,
but 漏掉最重要的问题 —— 让我们打开 IE 浏览器:
出现这个问题也是见怪不怪了,JS 语法也得往低兼容,babel 这个都不陌生把
安装 babel-loader
,不过这个插件呢也依赖了其他插件:@babel/core
,@babel/plugin-transform-runtime
,@babel/preset-env
npm i babel-loader @babel/core @babel/plugin-transform-runtime @babel/preset-env -D
- webpack.base.js
添加一下转换,排除 node_modules 的包
module.exports = {
module: {
rules: [
// ...
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}
}
}
]
}
// ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
然后重新运行项目,到 IE 看看情况: 冇得问题
打包,然后用 http-serve 运行看看(主要想验证下打包会不会出 bug),记得要用 http-serve。不然预览不了
js 的语法转化也 OK 了。看来写配置越来越顺利了!
# 整理项目资源
在 v0.0.2 收官之前,重新看下我们写的配置:webpack-base.js
,webpack-dev.js
,webpack-prod.js
。公共的地方有啥:
2 个公共目录
- ROOT_PATH
- path.resolve(ROOT_PATH, 'dist')
这一块也是先做一个迁移,写一个公共的配置文件把,这样不论配置文件走到哪里,目录基本都不会乱
在 build
文件夹下新建一个PATH.js
,存放我们项目要用的常用的目录
整理了几个文件夹,打包后的 dist 文件目录,还有模版文件的 index.html 文件,入口文件等,整理这部分也是为后面的多入口页面做铺垫了
- build/PATH.js
const path = require('path')
const ROOT = path.resolve(__dirname, '../')
const DIST = path.resolve(ROOT, 'dist')
const tmp_main = path.resolve(ROOT, 'src/main.js')
const TEMPLATE_HTML = path.resolve(ROOT, 'public/index.html')
module.exports = {
ROOT,
DIST,
TEMPLATE_HTML,
tmp_main
}
2
3
4
5
6
7
8
9
10
11
12
13
- webpack.base.js
// 注意2个地方被注释掉了,统一从PATH引入
// const path = require('path')
// const ROOT_PATH = path.resolve(__dirname, '../')
const { DIST, tmp_main, TEMPLATE_HTML } = require('./PATH')
module.exports = {
output: {
filename: '[name].[contenthash].js',
publicPath: './',
path: DIST // 改动了这里的PATH
},
// ...
plugins: [
// ...
// 设置html模板生成路径
new HtmlWebpackPlugins({
filename: 'index.html',
template: TEMPLATE_HTML, // 改了 template 的目录
chunks: ['main'] // 指定在html自动引入的js打包文件
})
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- webpack-dev.js 和 webpack-prod.js 2 个文件改动地方也是一样的了,就不重复写了
// 注意2个地方被注释掉了,统一从PATH引入
// const path = require('path')
// const ROOT_PATH = path.resolve(__dirname, '../')
const { DIST } = require('./PATH')
// output.path 改一下为 DIST 就可以了
2
3
4
5
6
# 最后
webpack 踩坑系列(二)也算是结束了~。介绍了使用 less,css 的样式分离,css 前缀补全,为了兼容 IE 老大哥做的 JS 转换
变动文件如下:
不过现在项目还是打包了一个页面,而我的想法是做一个 多入口的单页面应用
。做的可能没 nuxt
那么厉害那么复杂,不过在一定意义上可以减少首屏加载的问题~
下期预告:
- 当前项目的热更新是属于哪种热更新?
- 实现一个简单的多入口
- 实现自动获取入口(重头戏)
- 添加代码运行后的URL输出