1. webpack中的resolve 配置
在前面的项目中, src/main.js中引入 vue库是这样引入的:
import Vue from 'vue/dist/vue.js'
import App from './components/App.vue'
Vue.component("App",App)
new Vue({
el: '#app',
template: '<App />',
})
npm 引入的库文件都在 node_modules中,webpack在处理main.js入口文件的时候,会根据vue/dist/vue.js 路径到 node_modules中找到这个js,然后与当前的main.js 文件合并到一起。
有些库文件的目录比较深,而且有可能会被多次 import,为了方便解析这些引入的路径,webpack提供了resolve选项配置。Webpack 在启动后会从配置的入口模块出发找出所有依赖的模块,resolve 选项配置 Webpack 如何寻找模块所对应的文件,在resolve中可以为这些路径配置别名和文件的扩展名。 下面配置两个别名和一个扩展名:
webpack.conf.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: {
...
},
output: {
...
},
resolve: {
//配置了扩展名后,当我们引入库文件的时候就可以省略下面配的扩展名了
//下面配置了 .js 和 .vue, 这样一来我们在import的时候,就可以省略这两个扩展名了。
extensions: ['.js', '.vue'],
//别名配置 vue$ 是一个正则表达式,我们导入vue库的时候这样写 import Vue from 'vue',有了别名webpack就会处理成 import Vue from 'vue/dist/vue.js'
// @符号也是一个别名,它替代了项目的根目录。 path.join方法是 NodeJs path库的方法,用于连接路径 path.join(__dirname, 'src') 实际上就是项目的根目录。引入 App.vue文件的时候,就可以这样写 import App from '@/components/App.vue' ,webpack解析的时候,会用项目根目录把@替换掉,这样我们在引入文件的时候就更加方便。
alias: {
'vue$': 'vue/dist/vue.js',
'@': path.join(__dirname, 'src'),
}
},
module: {
...
},
plugins: [
...
]
}
src/main.js 导入文件现在就可以这样来写了:
// vue会匹配上配置的别名,实际是 vue/dist/vue.js,webpack会自动到 node_modules文件夹中寻找
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了。
import App from '@/components/App'
Vue.component("App",App)
new Vue({
el: '#app',
template: '<App />',
})
2. Vue的不同版本
下面是官方文档中对Vue版本号的说明:
可以看到有两种版本: Runtime+Compiler 版本(完整版)和 Runtime Only 版本 (运行时版)
我们知道Vue中渲染视图的时候,使用的是template绑定数据,对于这个template,Vue必须要编译成虚拟Dom的,那什么时候编译就有两种选择,一种选择就是运行的时候编译,这种情况下引入的Vue的版本就必须是 Runtime+Compiler,也就是完整版本。因为包含了Compiler部分,所以它编译出来的文件的体积更大。
一种选择是采用预编译的方式,将模板事先编译成 一个render函数,运行的时候直接调用render函数渲染即可。如果采用了预编译方式,那么仅仅使用 Runtinme Only版本的Vue库就够了,预编译出来的文件体积也更小。
先前我们使用的库是 vue/dist/vue.js 这个版本,我们先使用这个库来构建main.js, 构建出来的文件大小如下:
dist/index_eccc6bfd3df547cd15f3.js
我们使用ES6 的import导入方式导入Vue库的,现在试一试 vue.esm.js 这个完整版本,它用在基于构建工具的时候使用,因为 webpack中配置了别名,所以只需要修改配置的别名即可:
webpack.config.js
...
module.exports = {
...
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.join(__dirname, 'src'),
}
}
...
}
src/main.js 文件如下:
// vue会匹配上配置的别名,实际是 vue/dist/vue.esm.js
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了。
import App from '@/components/App'
Vue.component("App",App)
new Vue({
el: '#app',
template: '<App />',
})
构建完成之后,结果如下:
dist/index_ab5097ef61c11ef48859.js
可以看到体积变小了将近20K
下面再引入 Runtime Only 版本试一试:
webpack.config.js
...
module.exports = {
...
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js',
'@': path.join(__dirname, 'src'),
}
}
...
}
src/mian.js 保持不变:
// vue会匹配上配置的别名,实际是 vue/dist/vue.runtime.esm.js
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了。
import App from '@/components/App'
Vue.component("App",App)
new Vue({
el: '#app',
template: '<App />',
})
先不要着急 npm run build ,我们先 npm run dev , 服务正常启动,但是浏览器执行却出错了:
原因在于我们在 src/main.js 中 new Vue的时候传入了 template,如果这里传入template,那么Vue在运行的时候,需要对这个template进行编译,但我们使用的是 runtime-only 这个版本的vue,这个版本中没有编译器,是没有办法编译的。 我们说runtime-only 的版本对 template进行了预编译,都预编译成了render函数,要想正常渲染,就不能指定template了,需要指定 render函数。
src/main.js new Vue 的时候需要更改成这样:
// vue会匹配上配置的别名,实际是 vue/dist/vue.runtime.esm.js,webpack会自动到 node_modules文件夹中寻找
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了。
import App from '@/components/App'
Vue.component("App",App)
new Vue({
el: '#app',
render: function(createElement){//createElement是一个函数可以创建虚拟DOM
return createElement(App)
}
//通常被写成这样 runder: h=>h(App) 使用ES6 的箭头函数可以简写成这样,参数名称不一定非得是createElement
})
这样在运行就没有问题了。
现在npm run build 看看结果:
dist/index_96fa096c772db7d04440.js
可以看到,文件大小又减少了将近30k。 所以我们在生产环境中发布应用的时候,尽量采用 Runtime Only版本来发布。
3.组件样式
Vue的组件通常使用 .vue文件来编写,.vue文件由 template ,script, style三个标签组成。在style标签中编写样式。下面来看看在这里编写的样式最终被编译到哪里去了。
打开src/components/App.vue文件,代码如下:
<template>
<div>
<div class="box"></div>
</div>
</template>
<script>
export default {
data() {
return {
}
}
};
</script>
<style>
.box{
border:1px solid red;
width:300px;
height:50px;
}
</style>
这里仅仅为一个div添加了一个类样式。使用 npm run dev
启动服务:
可以看到webpack处理后,编写的样式被插入到了HTML的 style标签上了。再运行npm run build
进行编译打包,dist/index.html文件内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue入门</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="index_558634c76bb7dd6e3754.js"></script></body>
</html>
生成的HTML中,并没有style标签。原因是 webpack将css这种静态资源作为字符串“编译”到 Js文件中了。打开js文件可以看到css字符串
也就是说当HTML页面加载js文件后,JS代码运行的时候将会在HTML文档中创建 style节点,然后将style字符串输出到这个节点中。
3.1 局部样式与全局样式
src/components/App.vue文件中,定义样式的时候,这样写:
<style>
.box{
border:1px solid red;
width:300px;
height:50px;
}
</style>
这段代码将会被插入到HTML页面的style标签中。这个样式的有效范围就是全局范围。一个Vue应用其实就是由很多的组件组成的,现在只有一个 App.vue组件,将来还会编写很多vue组件,每个组件中都会编写样式,而这些样式都会被插入到HTML的style标签中而成为全局样式,项目大了之后,组件之间的样式就会出现冲突。
那如何做到样式只在当前组件有效,让其它组件无法使用?只需要在 style标签中添加一个 scoped属性即可:
<style scoped>
.box{
border:1px solid red;
width:300px;
height:50px;
}
</style>
现在看看运行后的结果:
会发现webpack在处理css的时候,为 div标签上添加了一个 data-v-xxx的属性,css样式的 .box后面添加了这个data-v-xxx 。 这样组件内定义的样式就相当于做到了局部有效(只在组件内有效)
3.2 使用sass
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。 官方文档: https://www.sass.hk/docs/
按照Sass语法编写的样式是不能够直接在浏览器中运行的,需要转换之后才能工作。这个可以为 webpack配置转换的loader。
src/components/App.vue
<template>
<div>
<div class="box"></div>
</div>
</template>
<script>
export default {
data() {
return {
}
}
};
</script>
<style lang='scss' scoped>
/* 定义一个变量 */
$primary-color: red;
.box{
border:1px solid $primary-color; /* 使用变量 */
width:300px;
height:50px;
}
</style>
在style上面添加了一个 lang=‘scss’ 这样webpack在处理的时候,就知道样式是用 sass语法写的
因为sass独立的样式文件通常用 .scss作为后缀,所以这里的lang用的是 scss
现在webpack还不能处理scss,需要安装loader在webpack.config.js中进行配置才行。
cnpm i sass-loader node-sass css-loader style-loader -D
因为sass-loader依赖于node-sass ,还会用到 css-loader和style-loader 。
package.json中的devDependencies 如下:
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5",
"clean-webpack-plugin": "^2.0.1",
"css-loader": "^2.1.1",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.11.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"vue-loader": "^15.7.0",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
webpack.config.js中的配置:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
...
module: {
rules: [{ //支持ES6 语法 转换
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.vue$/, //解析vue文件
loader: 'vue-loader'
}, {
//它会应用到普通的 `.css` 文件,以及 `.vue` 文件中的 `<style>` 块
//use数组loader的名字是有顺序的,即先由css-loader处理,再由vue-style-loader处理
test: /\.css$/,
use: ['vue-style-loader','css-loader']
},{
test: /\.scss$/,
//先由sass-loader 处理成css语法,然后由css-loader处理,最后由 style-loader处理
use: ['style-loader', 'css-loader', 'sass-loader']
}]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.tpl'
}),
new VueLoaderPlugin() // VueLoader插件
]
}
配置好了之后,执行效果如下:
我们发现scss代码不见了,已经被转换成css代码了。
4. 应用程序公共样式
编写应用的时候,往往会定义一些公共的样式,这样每个组件都能够直接使用。在项目的src目录中新建一个assets 文件夹,这个文件夹中存放一些静态资源,如样式,图片,字体文件等。
src/assets/css/common.scss
//全局公共样式
.success { color: #5cb85c}
.info { color: #5bc0de}
.error {color: #d9534f}
.warning {color: #ec971f}
要想让这个文件生效,就必须使用import 语句进行导入。对于webpack来说,一切都是资源。使用了import之后,webpack会将资源导入。公共的样式只需要在入口文件中导入即可:
src/main.js 导入css文件
// vue会匹配上配置的别名,实际是 vue/dist/vue.runtime.esm.js
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了
import App from '@/components/App'
//webpack.config.js中如果在 resolve.extensions 中配置了scss扩展名,这里的扩展名也可以省略
import '@/assets/css/common.scss'
Vue.component("App",App)
new Vue({
el: '#app',
render: h=>h(App)
})
在 src/components/App.vue中使用全局样式:
<template>
<div>
<div class="box">box类样式在App.vue中定义</div>
<div class="box success">success样式在common.scss文件中定义</div>
</div>
</template>
<script>
export default {};
</script>
<style lang='scss' scoped>
/* 定义一个变量 */
$primary-color: red;
.box{
border:1px solid $primary-color; /* 使用变量 */
width:300px;
height:50px;
}
</style>
执行效果:
可以看到 App.vue和 common.scss中的样式都使用style标签插入到了html文件中了。
5. 静态资源
静态资源(Assets)是指项目中被引用的各种格式的图片和字体文件,当然也可能包含各式各样其他扩展名的文件(.json,.xml等),这些资源通常会在JavaScript程序和CSS中使用。
在src/assets 文件夹中创建一个images文件夹,用来存放各种图片,拷贝三张图片到images文件夹中
这两张图片分资源分别在 JavaScript ,CSS,HTML中来使用。编辑 src/components/App.vue文件
<template>
<div>
<div id="vue-logo"></div>
<div>
<!-- html标签中使用 与在css中的用法相同,使用相对路径-->
<img src="../assets/images/webpack.png" />
</div>
<div>
<img :src='html5Img' />
</div>
</div>
</template>
<script>
//JavaScript代码中必须使用import 将文件作为模块导入,@符号是src文件夹所在的目录的别名
// html5Img 变量中存储的是图片资源的路径
import html5Img from '@/assets/images/html5.jpg'
export default {
data() {
return {
// javaScript代码中使用图片资源
html5Img
}
}
};
</script>
<style lang='scss' scoped>
#vue-logo{
width: 200px;
height: 200px;
//css中使用图片资源注意这里需要使用相对路径。注意这里不能使用@,只能是相对路径
// ..表示当前文件 src/components/App.vue 文件所在的路径 src/components的上一级目录
background-image: url('../assets/images/vue-logo.png')
}
</style>
因为前面在 Webpack中已经配置了 @就是应用的src目录,所以这里所有使用图片的路径都从src目录开始。 但是 npm run dev 后发现启动报告了 import html5Img from ‘@/assets/images/html5.jpg’ 有错误,无法解析文件
ERROR in ./src/assets/images/html5.jpg 1:0
Module parse failed: Unexpected character
因为webpack把所有的资源都当成模块来处理,各种资源需要配置对应的loader才能够正常处理。先前配置的vue-loader 能够正常处理css和HTML代码中的图片资源,但是对于JavaScript中导入的图片资源无法解析。
5.1 使用file-loader
webpack通过file-loader处理资源文件,它会将rules规则命中的资源文件按照配置的信息(路径,名称等)输出到指定目录,并返回其资源定位地址,默认的输出名是以原文件内容计算的MD5 Hash命名的。官方文档:https://www.webpackjs.com/loaders/file-loader/
cnpm i file-loader -D
webpack.config.js 文件配置:
...
module.exports = {
...
module: {
rules: [
...
,{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, //匹配图片文件
loader: 'file-loader',
options: {
outputPath: 'assets/img' //将图片输出到 dist/assets/img文件夹下
}
}]
},
...
}
配置了 file-loader之后启动正常
运行 npm run build 发现 src/assets/images中的文件被编译到了 dist/assets/img文件夹中
5.2 使用url-loader 引用优化
如果项目中的图片特别多,而每个图片又非常小,网页被浏览器加载之后,因为小图片很多就需要向服务器多次发起请求来获取图片二进制资源,这样就增加了服务器的负担。
既然每个图片文件都很小,此时可以直接将小图片的二进制对应的Base64字符串编译到JavaScript代码或者css代码中,这样浏览器加载js或css文件后,就不用再向服务器发起请求了。
用webpack 的 url-loader 来优化项目中对于资源的引用路径,并设定大小限制,当资源的体积小于limit时将其直接进行Base64转换后嵌入引用文件,体积大于limit时可通过fallback参数指定的loader进行处理。我们可以指定体积大于limit限制后,使用 file-loader来解析图片文件。
cnpm i url-loader -D
webpack.config.js 此时只需要配置 url-loader即可,无需单独配置 file-loader。因为url-loader上会指定超过限制的图片交给 file-loader来处理
...
module.exports = {
...
module: {
rules: [
...
,{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, //匹配图片文件
loader: 'url-loader',
options: {
limit:20480,//小于limit限制的图片将转为base64嵌入引用位置
fallback:'file-loader',//大于limit限制的将转交给指定的file-loader处理
outputPath:'assets/img'//传入file-loader将图片输出到 dist/assets/img文件夹下
}
}]
},
...
}
本例中的文件大小分别是:
- html5.jpg 13253字节,12.9K
- vue-logo.png 6849 字节 6.68K
- webpack.png 21633字节 21.1K
limit设定的是 20480字节,即20K, 所以html5.jpg和vue-logo.png会被处理成Base64编码嵌入到文件中,而webpack.png文件依然作为二进制存在。
npm run build 后,dist文件夹如下:
6. 将样式提取到css文件中
目前所有的css样式都被webpack处理成插入到html的style标签中,也可以让webpack将style标签中的内容“提取”到一个样式文件中,而且对css进行压缩处理(去掉注释,空格,换行等)。这需要为webpack配置插件来完成提取和压缩的功能。
webpack4中使用 mini-css-extract-plugin 官方文档 https://webpack.js.org/plugins/mini-css-extract-plugin/#minimizing-for-production 来提取css样式, 使用 optimize-css-assets-webpack-plugin 来压缩css
安装插件:
cnpm i mini-css-extract-plugin optimize-css-assets-webpack-plugin -D
webpack.config.js中配置插件:
...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//提取css到单独文件的插件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');//压缩css插件
module.exports = {
...
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.vue$/,
loader: 'vue-loader'
},{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, //匹配图片文件
loader: 'url-loader',
options: {
limit:20480,//小于limit限制的图片将转为base64嵌入引用位置
fallback:'file-loader',//大于limit限制的将转交给指定的loader处理
outputPath:'assets/img'//传入file-loader,将图片输出到 dist/assets/img文件夹下
}
}, {
test: /\.css$/,//最后一步由MiniCssExtractPlugin.loader来处理
use: [ MiniCssExtractPlugin.loader,'css-loader']
},{
test: /\.scss$/,//最后一步由MiniCssExtractPlugin.loader来处理
use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.tpl'
}),
new VueLoaderPlugin(),
//抽取css的插件
new MiniCssExtractPlugin({
filename: "assets/css/[name]_[hash].css"//输出目录与文件
}),
new OptimizeCssAssetsPlugin()
]
}
需要注意的是: MiniCssExtractPlugin 还需要在 loader上配置一下,MiniCssExtractPlugin 提供了一个loader,在module.rules.use 组数的第一个元素位置上配上这个loader表示文件处理的最后一步交给 这个loader来处理。一定要注意顺序。plugins中配置了插件,并指定了提取的css文件的存储路径和文件名。[name]是入口文件的name。
可以看到,最终html文件中自动加入了link标签将生成的css文件引入。html中再无style标签,因为webpack已经通过MiniCssExtractPlugin提取到css文件中了,并且去掉了空格,换行,注释,说明已经被“压缩”过了。
7 使用第三方样式库
第三方提供了很多已经写好的样式库,如bootstrap,element(饿了么针对Vue的组件样式库),阿里图标库等。
7.1 使用bootstrap
bootstrap中有些组件使用了jQuery,所以导入bootstrap的同时也需要导入jQuery。bootstrap和jQuery是最终发布的时候要使用的,所以需要使用 -S参数
cnpm i bootstrap@3.3.7 jquery -S
bootstrap中依赖了字体图标文件(.ttf .woff .woff2 .eot .svg ),和图片文件。这些资源文件用 url-loader来处理即可,所以还需要安装 url-loader, 它只是在构建阶段用到,所以使用 -D参数
现在package.json文件是这样的:
"dependencies": {
"bootstrap": "^3.3.7",
"jquery": "^3.3.1",
"vue": "^2.6.10"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5",
"clean-webpack-plugin": "^2.0.1",
"css-loader": "^2.1.1",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"vue-loader": "^15.7.0",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
webpack.config.js文件中配置 url-loader用来处理字体文件和图片文件和视频文件
...
module.exports = {
...
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.vue$/,
loader: 'vue-loader'
}, {
test: /\.css$/,
use: [ MiniCssExtractPlugin.loader,'css-loader']
},{
test: /\.scss$/,
use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
},{
//处理图片文件
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit:10240 ,//小于limit限制的图片将转为base64嵌入引用位置
fallback:'file-loader',//大于limit限制的将转交给指定的loader处理
outputPath:'assets/img'//传入file-loader,将图片输出到 dist/assets/img文件夹下
}
},{
//处理字体文件
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit:10240 ,
fallback:'file-loader',
outputPath:'assets/fonts' //存放到fonts目录下
}
},{
//处理音视频文件
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit:10240 ,
fallback:'file-loader',
outputPath:'assets/media' //存放到media目录下
}
}]
...
}
bootstrap模块的js代码中用到了jQuery库,如果不引入jQuery,那么这些jQuery库是无法使用的。webpack中提供了一个内置的ProvidePlugin ,它可以直接使用 webpack.ProvidePlugin
来获取插件对象,不需要安装。官方文档:https://webpack.docschina.org/plugins/provide-plugin/ .
webpack.config.js
...
module.exports = {
...
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.tpl'
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: "assets/css/[name]_[hash].css"//输出目录
}),
new OptimizeCssAssetsPlugin(),
//将两个变量都指向对应的 node 模块,这样第三方依赖jQuery的库就可以正常使用了。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
}
一般我们将bootstrap库用在全局,所以只需要在 src/main.js中引入即可
// vue会匹配上配置的别名,实际是 vue/dist/vue.runtime.esm.js
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了
import App from '@/components/App'
import 'bootstrap/dist/css/bootstrap.css'
//省略了js扩展名,实际是bootstrap/dist/js/bootstrap.js
import 'bootstrap/dist/js/bootstrap'
import '@/assets/css/common.scss'
Vue.component("App",App)
new Vue({
el: '#app',
render: h=>h(App)
})
可以看到bootstrap样式库,自定义的common.scss和 组件定义的css全部都打包到了 css文件中了。
npm run build之后的dist目录:
7.2 webpack配置中output.publicPath的作用
使用上面的配置 npm run build以后, bootstrap的字体文件被放到了 assets/fonts目录中,使用的配置为:
{
//处理字体文件
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit:10240 ,
fallback:'file-loader',
outputPath:'assets/fonts' //存放到fonts目录下
}
}
而css文件被放在了 assets/css/index_xxx.css 目录中, 现在来看看 这个css文件中有关字体文件引用的代码:(打开编译以后的css文件发现已经被压缩过了,可以将这个文件用 vs code工具打开,然后进行格式化):
@font-face {
font-family: Glyphicons Halflings;
src: url(assets/fonts/glyphicons-halflings-regular.f4769f9.eot);
src: url(assets/fonts/glyphicons-halflings-regular.f4769f9.eot?#iefix) format("embedded-opentype"),
url(assets/fonts/glyphicons-halflings-regular.448c34a.woff2) format("woff2"),
url(assets/fonts/glyphicons-halflings-regular.fa27723.woff) format("woff"),
url(assets/fonts/glyphicons-halflings-regular.e18bbf6.ttf) format("truetype"),
url(assets/glyphicons-halflings-regular.8988968.svg#glyphicons_halflingsregular) format("svg")
}
index.html文件在根目录中(dist),这样引入了index_xxx.css
<link href='assets/css/index_xxx.css' rel=stylesheet>
注意看所有的路径都是以assets开头的,是一个相对路径
index.html在根目录下,所以根目录下的 assets/css/index_xxx.css 这个css文件能够被正确加载。但是当 index_xxx.css文件中要加载字体文件的时候,因为字体文件使用的是 assets/fonts/xxx.yyy
这种相对路径,此时这种相对路径就会被解析成 assets/css/assets/fonts/xxx.yyy ,显然这个路径是错误的。
如果webpack在输出所有路径的时候,能够在所有的相对路径前面添加一个前缀,让这个路径变成绝对路径,或者让所有的路径都从根开始,这样就不存在问题了。webpack配置选项output.publicPath 就可以做这件事情:
...
module.exports = {
entry: {
index: './src/main.js'
},
output: {
//所有的路径在输出的时候,都加上 '/',让路径从根目录开始。
//生产环境下可以配置成 "http://www.mydomian.com/"的形式
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
filename: '[name]_[hash].js'
},
...
}
如果publicpath配置成 ‘/’ 或者 http://www.mydomian.com/ , 那么html文件中引用css就变成了:
<link href='/assets/css/index_xxx.css' rel=stylesheet>
或者
<link href='http://www.mydomian.com/assets/css/index_xxx.css' rel=stylesheet>
css文件中关于字体的引用就变成了:
@font-face {
font-family: Glyphicons Halflings;
src: url(/assets/fonts/glyphicons-halflings-regular.f4769f9.eot);
src: url(/assets/fonts/glyphicons-halflings-regular.f4769f9.eot?#iefix) format("embedded-opentype"),
...
}
或者
@font-face {
font-family: Glyphicons Halflings;
src: url(http://www.mydomian.com/assets/fonts/glyphicons-halflings-regular.f4769f9.eot);
...
}
测试环境下使用 ‘/’ ,生产环境下配置成域名,或CDN地址
7.3 使用阿里字体库
登录阿里图标库 https://www.iconfont.cn,将需要用到的图标加入购物车后添加到项目。可以生成在线地址,然后在 index.tpl中引入后就可以使用了。
这里我们采用下载到本地的方式使用:
这种下载下来的文件是无法用npm来进行安装的,将他们拷贝到项目中的 src/assets/icon文件夹中:
参照 demo_index.html,我们只需要引入css文件即可。
src/main.js 文件
// vue会匹配上配置的别名,实际是 vue/dist/vue.runtime.esm.js
import Vue from 'vue'
//@ 实际上是项目根目录的别名,因为配置了vue扩展名,这里就可以省略了
import App from '@/components/App'
import 'bootstrap/dist/css/bootstrap.css'
//省略了js扩展名,实际是bootstrap/dist/js/bootstrap.js
import 'bootstrap/dist/js/bootstrap'
//引入阿里图标库css文件
import '@/assets/icon/iconfont.css'
import '@/assets/css/common.scss'
Vue.component("App",App)
new Vue({
el: '#app',
render: h=>h(App)
})
在 src/components/App.vue中使用图标库
<template>
<div>
<div class="box">box类样式在App.vue中定义</div>
<div class="box success">success样式在common.scss文件中定义</div>
<button class="btn btn-primary">bootstrap按钮(Primary)</button>
<button class="btn btn-info">bootstrap按钮(info)</button>
<button class="btn btn-success">bootstrap按钮(success)</button>
<br />
<span class="iconfont icon-icon_alipay_line" style=" font-size:35px;color:red "></span>使用阿里图标库中的图标
</div>
</template>
<script>
export default {};
</script>
<style lang='scss' scoped>
/* 定义一个变量 */
$primary-color: red;
.box{
border:1px solid $primary-color; /* 使用变量 */
width:300px;
height:30px;
}
</style>
这几个字体文件都不超过10K,所以他们都会用Base64格式内嵌到样式文件中。