1 基本配置
1 配置webpack
参考官网的例子webpack官网
webpack版本:4.32.0
main.js
import bar from './bar';
bar();
src/bar.js
export default function bar() {
console.log('我来自bar.js')
}
webpack.config.js
没有的话在项目根目录下面新建
const path = require('path');
//path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。
module.exports = {
entry: './src/main.js',//入口
output: {//输出
path: path.resolve(__dirname, 'dist'),//输出的路径
filename: 'bundle.js'//输出的文件名
}
};
参考node.js path.resolve
index.html
<html>
<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>不要脚手架</title>
</head>
<body>
<h1>hello world</h1>
<div id="root"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
现在还需要安装webpack-cli -D
和webpack -D
,也可以运行npx webpack
(npx需要提前全局安装)或者在package.json scripts
中添加:
"scripts": {
"dev": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
在终端中输入
npm run dev
用浏览器打开index.html:
优化:增加webpack-dev-server
webpack-dev-server: 为你提供了一个简单的 web server,并且具有 live reloading(实时重新加载) 功能。
//终端
npm install webpack webpack-dev-server webpack-cli -D
在webpack后面加上--mode devlopment或者production
参考:webpack mode
配置package.json
"dev":"webpack-dev-server --mode development --open",
"start": "npm run clear && webpack --mode development && npm run dev",
"build": "webpack --mode production",
"clear": "rimraf dist"
clear:清空dist
webpack-dev-server:开启一个本地服务器
//终端
npm run start
现在可以在可以看到项目在浏览器上运行了
2 配置vue项目
先把之前的bar.js删除
2.1 安装vue
npm i vue -S
在src目录下面新建app.vue文件
这里推荐本人的插件:auto-vue-file
https://github.com/huoguozhang/auto-vue-file
在命令行输入auto-vue-file -p --path ./src
回车输入组件名:App,自动创建App.vue文件
注意:咱们目前还没有支持scss, 先把App.vuelang="scss"
去掉
写入如下代码:
//app.vue
<template>
<div class="App-comp-ct">
App组件
<p>{{msg}}</p>
<Home></Home>
</div>
</template>
<script>
import Home from './home.vue'
export default {
name: 'App',
components: {
Home
},
data () {
return {
msg: 'vue zero config'
}
}
}
</script>
<style scoped>
.App-comp-ct {
}
</style>
新建home.vue文件
//home.vue
<template>
<div class="home-comp-ct">
home组件
</div>
</template>
<script>
export default {
name: 'home'
}
</script>
<style scoped>
.home-comp-ct {
}
</style>
修改main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
el:'#root',
render: h => h(App)
})
根目录新建:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
执行npm run start
报错了:
建议我可能需要loader来处理xxx.vue的文件
因为webpack是一个前端打包工具,默认只能打包
*.js
文件,其他后缀的文件需要特定的loader来支持。参考:webpack-概念
名词解释:
参数 | 说明 |
---|---|
entry | 项目入口 |
module | 开发中每一个文件都可以看做 module,模块不局限于 js,也包含 css、图片等 |
chunk | 代码块,一个 chunk 可以由多个模块组成 |
loader | 模块转化器,模块的处理器,对模块进行转换处理 |
plugin | 扩展插件,插件可以处理 chunk,也可以对最后的打包结果进行处理,可以完成 loader 完不成的任务 |
bundle | 最终打包完成的文件,一般就是和 chunk 一一对应的关系,bundle 就是对 chunk 进行便意压缩打包等处理后的产出 |
.vue文件就需要vue-loader支持
vue-loader
安装:npm i vue-loader vue-template-compiler -D
配置
//webpack.config.js
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module:{
rules:[
{
test: /\.vue$/, // 匹配到该的文件由该规则处理
use: 'vue-loader'
}
]
}
}
依次安装提示缺少得东西:
css-loader(解析css文件)
vue-style-loader(style-loader加强版不需要你自己配置)
npm i vue-style-loader css-loader -D
//配置loader
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {
rules: [
// ... other rules
{
test: /\.vue$/,
loader: 'vue-loader'
},
// this will apply to both plain `.css` files
// AND `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
]
},
plugins: [
// make sure to include the plugin!
new VueLoaderPlugin()
]
}
现在vue能编译了,怕样式覆盖可以直接加scoped
3 js和css分离
上一步骤中运行起来是没有问题了,但是样式全部插在head里面作为style标签。所以能以link的方式加载css多好啊!
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {
rules: [
// ... other rules
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
// make sure to include the plugin!
new ExtractTextPlugin('style.css'),
new VueLoaderPlugin()
]
}
执行的时候会报一个错:
执行:
npm install extract-text-webpack-plugin@nex
然后执行:
npm run start
可以看到dist目录下面已经有style.css了
把style.css添加到index.html中就可以看到效果了
//index.html
<link rel="stylesheet" href="style.css">
4 自动加到index.html上
前言:上一步分离出来的js文件和css文件需要我们手动去加上,这显然是不合理的
htmlWebpackPlugin插件能满足我的需求:https://webpack.docschina.org/plugins/html-webpack-plugin/
npm install -D html-webpack-plugin
更改文件:
1 把index.html的link和script标签去掉
2 这里先把package.json改一下:
"build": "npm run clear && webpack --mode production"
3 更改一下webpack.config.js
配置说明:https://github.com/jantimon/html-webpack-plugin#options
...
+ const HtmlWebpackPlugin = require('html-webpack-plugin')
...
plugins: [
new VueLoaderPlugin(),
new ExtractTextPlugin('./style.css'),
+ new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
4 将htttp-server(需安装)运行在dist目录下面,查看效果:
5 处理图片等其他静态资源
在src/assets/img/目录中新增一张图片:dog.jpg
把图片加到home组件中:
<div class="home-comp-ct">
home组件
<img src="./assets/img/dog.jpg" alt="狗狗">
</div>
执行npm run build
报错:
npm install url-loader -D
url-loader说明:
const assetsPath = function (_path) {
const assetsSubDirectory = 'static'
return path.posix.join(assetsSubDirectory, _path)
}
//webpack.config.js
// module rules 增加一条规则
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: assetsPath('img/[name].[ext]')
}
},
build后查看:
6 配置:resolve
Webpack 进行构建的时候会从入口文件开始(entry)遍历寻找各个模块的依赖,resolve 配置是帮助 Webpack 查找依赖模块的,通过 resolve 的配置,可以帮助 Webpack 快速查找依赖,也可以替换对应的依赖(比如开发环境用 dev 版本的 lib 等)。
alias:resolve.alias 是最常用的配置,通过设置 alias 可以帮助 webpack 更快查找模块依赖,而且也能使我们编写代码更加方便。例如,我们在实际开发中经常会把源码都放到src文件夹。
extensions:resolve.extensions是帮助 Webpack 解析扩展名的配置,默认值:['.wasm', '.mjs', '.js', '.json'],所以我们引入 js 和 json 文件,可以不写它们的扩展名,通常我们可以加上 .css、.less等,但是要确保同一个目录下面没有重名的 css 或者 js 文件,如果存在的话,还是写全路径吧。
app.vue中可以改写为:
import Home from '@/home'
webpack.config.js
// entry :{},
// output: {},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.js', '.json', '.css', '.vue']
},
7:配置:output
webpack的output是指定了entry对应文件编译打包后的输出bundle。
对于不同的entry可以使用filename占位符来区分:
名称 | 含义 |
---|---|
[hash] | 模块标识符的 hash |
[chunkhash] | chunk 内容的 hash |
[name] | 模块名称 |
[id] | 模块标识符 |
[query] | 模块的 query,例如,文件名 ? 后面的字符串 |
一个常见的场景:如果我们发布一个新版的项目,浏览器误以为还是原来的文件(文件名没有变),可能会直接拿本地缓存。或者我们希望改变的文件不要缓存,没有改变的文件拿缓存,这样多美好啊!
output中的hash值能帮助我们:
hash:其根据每次编译内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变,hash长度默认20,可以自行设置长度。
三种不同的:hash
[hash]:是整个项目的 hash 值,其根据每次编译内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变;在一个项目中虽然入口不同,但是 hash 是相同的;hash 无法实现前端静态资源在浏览器上长缓存,这时候应该使用 chunkhash;
[chunkhash]:根据不同的入口文件(entry)进行依赖文件解析,构建对应的 chunk,生成相应的 hash;只要组成 entry 的模块文件没有变化,则对应的 hash 也是不变的,所以一般项目优化时,会将公共库代码拆分到一起,因为公共库代码变动较少的,使用 chunkhash 可以发挥最长缓存的作用;
[contenthash]:使用 chunkhash 存在一个问题,当在一个 JS 文件中引入了 CSS 文件,编译后它们的 hash 是相同的。而且,只要 JS 文件内容发生改变,与其关联的 CSS 文件 hash 也会改变,针对这种情况,可以把 CSS 从 JS 中使用mini-css-extract-plugin 或 extract-text-webpack-plugin抽离出来并使用 contenthash。
所以可以配置为:
主要文件为hash,引入的css文件为contentHash,第三方库为chunkHash
更改webpack.config.js文件:
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].[hash:7].js',
publicPath: './'
},
...
new ExtractTextPlugin({
filename: assetsPath('css/[name].[contenthash].css'),
allChunks: true
})
这里直接执行npm run build 会报一个错的
Error: Path variable [contenthash] not implemented in this context
可以参考:https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/763
将[contenthash]
改为[md5:contenthash:hex:20]
即可:
测试一下
删掉注释
css名没有变
配置babel和eslint
1. 配置babel
为什么要配置?因为老的浏览器不支持es6+呀,
比如:
//app.vue
created(){
new Promise((resolve,reject) =>{
setTimeout(()=>{
resolve('next')
},1000)
}).then((value)=>{
new Test().say()
console.log(value)
})
}
在ie11中打开
在chrome中打开
参考webpack官网进行配置
//webpack.config.js
{
test: /.(js)$/, //支持箭头函数,class等
loader: 'babel-loader',
exclude: [
path.join(__dirname, '../node_modules') // 由于node_modules都是编译过的文件,这里我们不让babel去处理其下面的js文件
]
},
项目根目录新建一个.babelrc文件
//.babelrc
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-0"
]
}
npm i bael-polyfill -s
让babel浏览器支持prosime和array.from等
修改entry
//webpack.config.js
entry: ["babel-polyfill",'./src/main.js'] ,
参考babel-polyfill
2. 配置eslint
1 安装:npm i eslint-loader eslint -s
2 在项目根目录下面新建.eslintrc.json
3 配置 .eslintrc.json
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"semi": 2
}
}
配置可参考官网样例
再跑起来,有很多不规范的代码书写0.0
css 预处理器配置
less-loader :先处理 less 语法
postcss-loader: 进行前缀添加等其他处理
css-loader: 将内容引入 @import 所在的 css 文件内
vue-style-loader: 将生成 style 标签,将 css 内容插入 HTML
postcss-loader配置可以参照postcss-loader
新建一个postcss.config.js在根目录
module.exports = {
plugins: {
// 处理 @import
'postcss-import': {},
// 处理 css 中 url
'postcss-url': {},
// 自动前缀
'autoprefixer': {
"browsers": [
"> 1%",
"last 2 versions"
]
}
}
}
如图:添加前缀成功
其他配置
resolve: { //导入的时候不用写拓展名
extensions: [' ', '.js', '.json', '.vue', '.scss', '.css']
},
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 300,//防止重复保存频繁重新编译,300ms内重复保存不打包
poll: 1000 //每秒询问的文件变更的次数
},
devServer:{
inline: true,
compress: true,
host: '127.0.0.1',
port: 2500,
historyApiFallback: true
}
webpack.config.js完整配置
const path=require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack=require('webpack')
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {
rules: [
// ... other rules
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|jpg|gif)$/,
use: [{ loader: 'url-loader',options: { limit: 8192 } }]
}
]
},
plugins: [
// make sure to include the plugin!
new ExtractTextPlugin('style.css'),
new VueLoaderPlugin(),
new webpack.HotModuleReplacementPlugin({
// Options...
})
],
resolve: { //导入的时候不用写拓展名
extensions: [' ', '.js', '.json', '.vue', '.scss', '.css']
},
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 300,//防止重复保存频繁重新编译,300ms内重复保存不打包
poll: 1000 //每秒询问的文件变更的次数
},
devServer:{
inline: true,
compress: true,
host: '127.0.0.1',
port: 2500,
historyApiFallback: true,
hot:true
}
}