webpack4从零配置vue项目

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 -Dwebpack -D,也可以运行npx webpack(npx需要提前全局安装)或者在package.json scripts中添加:

"scripts": {
    "dev": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

在终端中输入

npm run dev

用浏览器打开index.html:


image.png

image.png

优化:增加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

现在可以在可以看到项目在浏览器上运行了


image.png

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
报错了:

image.png

建议我可能需要loader来处理xxx.vue的文件
因为webpack是一个前端打包工具,默认只能打包*.js文件,其他后缀的文件需要特定的loader来支持。
参考:webpack-概念
image.png

名词解释:

参数 说明
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()
    ]
}

执行的时候会报一个错:

image.png

执行:npm install extract-text-webpack-plugin@nex
然后执行:npm run start
可以看到dist目录下面已经有style.css了
image.png

把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目录下面,查看效果:


image.png

5 处理图片等其他静态资源
在src/assets/img/目录中新增一张图片:dog.jpg
把图片加到home组件中:

<div class="home-comp-ct">
    home组件
    <img src="./assets/img/dog.jpg" alt="狗狗">
  </div>

执行npm run build
报错:

image.png

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后查看:

image.png

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中打开


image.png

在chrome中打开


image.png

参考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

image.png

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"
            ]
        }
    }
}

如图:添加前缀成功


image.png

其他配置

   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
    }
}

参考1: 从零开始的 webpack4 + vue2.x

参考2:Webpack 配置详解(含 4)——关注细节

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 1 Webpack 1.1 概念简介 1.1.1 WebPack是什么 1、一个打包工具 2、一个模块加载工具 3...
    Kevin_Junbaozi阅读 6,636评论 0 16
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 webpack介绍和使用 一、webpack介绍 1、由来 ...
    it筱竹阅读 11,027评论 0 21
  • webpack 介绍 webpack 是什么 为什么引入新的打包工具 webpack 核心思想 webpack 安...
    yxsGert阅读 6,447评论 2 71
  • 写在开头 先说说为什么要写这篇文章, 最初的原因是组里的小朋友们看了webpack文档后, 表情都是这样的: (摘...
    Lefter阅读 5,273评论 4 31
  • A区:人生目标关键词 时间管理/工作事业/个人提升/美丽健康/财务管理/家人情感/社会资本/ 今日关键词:时间管理...
    白菜姐英语阅读 119评论 0 0