webpack手动搭建vue2.0环境

基础常识:

查看版本号:

vue -V
webpack -v 查看当前版本

已有项目升级webpack到最新版:

删除node_modules目录
进入package.json文件修改版本号到最新
npm install --save-dev webpack

升级webpack到最新版:

删除node_modules目录
npm install --save-dev webpack
npm -v/cnpm -v

简介:此项目为vue2.x 使用webpack4构建项目的文档教程,自我学习保存。
前言:为了方便项目的存储,可以先在码云上建个仓库,git clone一下,然后修改下.gitignore文件 将node_modules/ 和 /dist/ 加入,最好从其他项目中复制一份过来。

好了,正文开始:

1.npm init 生成 packge.json文件

image.png

2.安装必要依赖

(1)npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev

image.png

webpack-cli: webpack中分离出来的
webpack-dev-server
webpack-merge

(2)npm i vue vue-router vuex --save

image.png

3.创建目录结构

|--dist
|--build
    |--webpack.prod.js
    |--webpack.dev.js
    |--webpack.base.js
|--src
    |--index.js
    |--app.vue
    |--router.js
    |--store.js
    |--assets
    |--components
    |--views
|--index.html

4.安装vue核心解析插件 npm i vue-loader vue-template-compiler --save-dev

5.安装其他的loader

在同一个 test 下配置多个loader时,优先处理的 loader 放在配置数组的后面
(1)必要的:

CSS 基础 loader:
css-loader: "^1.0.0", // 加载.css文件
style-loader: "^0.21.0", //使用<style>将css-loader内部样式注入到我们的HTML页面
file-loader// 解析图片,字体等
url-loader //设置上limit选项,将小于limit的图片转编码,大于limit的交给file-loader复制路径来引用使用

注意:具体参考vue-webpack模板,配置url-loader后不需要配置file-loader,但可在url-loader中添加name字段,file-loader会实现name字段内容。文末会放上build文件夹下,三个配置文件的代码。

npm i babel-core --save-dev
npm i @babel/core --save-dev
@babel/preset-env --save-dev // 是一个配置文件,我们可以使用这个配置文件转换 ES2015/ES2016/ES2017 到 ES5
babel-preset-env 这个是旧版本的

.babelrc文件:

{
  "presets": ["@babel/preset-env"]
}

npm i babel-loader --save-dev //可以把ES6语法转为ES5语法
npm i html-webpack-plugin --save-dev //安装 html 模板解析插件
npm i clean-webpack-plugin --save-dev //解决每次重新打包,dist 文件夹文件未清除

(2)选择性的:
CSS 前处理 less 两件套
"less": "^3.8.0",
"less-loader": "^4.1.0",
CSS 前处理 sass 两件套
"node-sass": "^4.9.2",
"sass-loader": "^7.1.0",
CSS 后处理 postcss 两件套
"postcss-loader": "^2.1.6",
"autoprefixer": "^9.1.0",
npm install mini-css-extract-plugin --save-dev //webpack4中分离CSS。插件来分离 css。

注意:这个插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR,具体看模板文件配置

npm install image-webpack-loader --save-dev //图片压缩
npm i optimize-css-assets-webpack-plugin --save-dev // css代码压缩,优化css结构,利于网页加载和渲染
npm i uglifyjs-webpack-plugin --save-dev // js代码压缩
npm i --save-dev cross-env 能跨平台地设置及使用环境变量,不同平台使用唯一指令,无需担心跨平台问题。

总结一下loader的常用四种写法:

use: [xxx, xxx]
use: [{loader: XXX}, {loader: XXX}]
use: [{
     loader: XXX,
     options: {}
}, 'XXX']
loader: [XXX, XXX]

loader的options配置项里面还可以放置loader,also plugins

常用的loader:

  • 处理样式的:style-loader,css-loader,postcss-loader,sass-loader,less-loder
  • 处理es6的:babel-loader(要连同babel-core, babel-preset-env)一起用
  • 处理图片的:file-loader, url-loader, image-webpack-loader

常用的plugin:

  • 压缩js:uglifyjs-webpack-plugin
  • 合并&压缩css: mini-css-extract-plugin,optimize-css-assets-webpack-plugin
  • 清除目录:clean-webpack-plugin
  • 生成html:html-webpack-plugin
  • postcss相关的:postcss-plugin-px2rem,postcss-preset-env,postcss-sprites,autoprefixer
  • webpack自带的方法:webpack.ProvidePlugin等

build文件夹下的配置文件:

webpack.base.js

// webpack.base.js
// 存放 dev 和 prod 通用配置
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
//mini-css-extract-plugin插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR
const devMode = process.env.NODE_ENV !== 'production';
//console.log(process.env.NODE_ENV,"devMode--------------")
//webpack4 分离css插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
//使用 WEBPACK_SERVE 环境变量检测当前是否是在 webpack-server 启动的开发环境中
//const dev = Boolean(process.env.WEBPACK_SERVE)
// 使用happypack---加速webpack打包
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({
  size: os.cpus().length
});


module.exports = {
  entry: './src/index.js', //入口
  /*
  配置各种类型文件的加载器,称之为 loader
  webpack 当遇到 import ... 时,会调用这里配置的 loader 对引用的文件进行编译
  */
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        // 正则匹配所有以.css结尾的文件
        // 它会应用到普通的 `.css` 文件
        // 以及 `.vue` 文件中的 `<style>` 块
        test: /\.(sa|sc|c)ss$/,
        // 使用css-loader和style-loader依次对css文件进行处理
        /*
        先使用 css-loader 处理,返回的结果交给 style-loader 处理。
        css-loader 将 css 内容存为 js 字符串,并且会把 background, 
        @font-face 等引用的图片,字体文件交给指定的 loader 打包,
        */
        // 按照数组中从后往前的顺序
        use: [
          devMode?'vue-style-loader':{
            loader:MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../'
            }
          },
          /***
            **还没有尝试css-loader的url属性是否可行
          ***/
          /* {
            loader: 'css-loader',
            options: {
              url: false, // css中加载图片的路径将不会被解析 不会改变
              minimize: true,   //
              importLoaders: 1
            }
          }, */
          'css-loader',
          'sass-loader'
        ]
      },
      // 图片处理
      {
        //test: /\.(gif|png|jpe?g|svg)$/i,
        test: /\.(png|jpg|jpeg|gif|svg|svgz)(\?.+)?$/,
        //enforce: 'pre',  // 这会应用该 loader,在其它之前
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192, //单位Bytes,即转换8KB以下的图
              // 当图片大于8192时,分离图片至imgs文件夹
              // [ext]是占位符 表示文件的后缀名
              /* name: devMode ? "img/[name].[ext]" : "img/[hash:6][name].[ext]" */
              name: devMode ? "[name].[ext]" : "[hash:6][name].[ext]",//和注释那行的效果一样
              publicPath: "./img/",
              outputPath: "img/"
              /* fallback: ['file-loader','image-webpack-loader'],
              quality: 85 */
            }
          },
          // 图片压缩
          //'file-loader',
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65
              },
              optipng: {
                enabled: false
              },
              pngquant: {
                quality: '65-90',
                speed: 4
              },
              gifsicle: {
                interlaced: false
              },
              webp: {
                quality: 75
              }
            }
          }
        ]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 8192,
          name: devMode ? "fonts/[name].[ext]" : "fonts/[hash:3][name].[ext]"
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/
        /* exclude: __dirname + 'node_modules',
        include: __dirname + 'src',
        options: {
          presets: ['env']
        } */
      },
      {
        test: /\.js$/,
        //把对.js 的文件处理交给id为happyBabel 的HappyPack 的实例执行
        loader: 'happypack/loader?id=happyBabel',
        //排除node_modules 目录下的文件
        exclude: /node_modules/
      }
      


    ]
  },
  /*
  配置 webpack 插件
  plugin 和 loader 的区别是,loader 是在 import 时根据不同的文件名,匹配不同的 loader 对这个文件做处理,
  而 plugin, 关注的不是文件的格式,而是在编译的各个阶段,会触发不同的事件,让你可以干预每个编译阶段。
  */
  plugins: [
    /*
    html-webpack-plugin 用来打包入口 html 文件
    entry 配置的入口是 js 文件,webpack 以 js 文件为入口,遇到 import, 用配置的 loader 加载引入文件
    但作为浏览器打开的入口 html, 是引用入口 js 的文件,它在整个编译过程的外面,
    所以,我们需要 html-webpack-plugin 来打包作为入口的 html 文件
    */
    new HtmlWebpackPlugin({
      /*
      template 参数指定入口 html 文件路径,插件会把这个文件交给 webpack 去编译,
      webpack 按照正常流程,找到 loaders 中 test 条件匹配的 loader 来编译,那么这里 html-loader 就是匹配的 loader
      html-loader 编译后产生的字符串,会由 html-webpack-plugin 储存为 html 文件到输出目录,默认文件名为 index.html
      可以通过 filename 参数指定输出的文件名
      html-webpack-plugin 也可以不指定 template 参数,它会使用默认的 html 模板。
      */
      template: path.resolve(__dirname, '../index.html'),
    }),
    new VueLoaderPlugin(),
    //
    new MiniCssExtractPlugin({
      filename: devMode ? 'css/[name].css' : 'css/[name].[hash:5].css',
      chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash:5].css',
    }),
    // 解决vender后面的hash每次都改变
    /*
    使用文件路径的 hash 作为 moduleId。
    虽然我们使用 [chunkhash] 作为 chunk 的输出名,但仍然不够。
    因为 chunk 内部的每个 module 都有一个 id,webpack 默认使用递增的数字作为 moduleId。
    如果引入了一个新文件或删掉一个文件,可能会导致其他文件的 moduleId 也发生改变,
    那么受影响的 module 所在的 chunk 的 [chunkhash] 就会发生改变,导致缓存失效。
    因此使用文件路径的 hash 作为 moduleId 来避免这个问题。
    */
    new webpack.HashedModuleIdsPlugin(),
    //happyPack实例
    new HappyPack({
      //用id来标识 happypack处理那里类文件
      id: 'happyBabel',
      //如何处理  用法和loader 的配置一样
      loaders: [{
        loader: 'babel-loader?cacheDirectory=true',
      }],
      //共享进程池
      threadPool: happyThreadPool,
      //允许 HappyPack 输出日志
      verbose: true,
      //启用debug 用于故障排查。
      debug: false
    }),
    //设置环境变量信息
    new webpack.DefinePlugin({
      //鸡肋功能?
      /* 'process.env':{
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      } */
    })

  ] // 插件
};

webpack.dev.js

// webpack.dev.js
// 存放 dev 配置
const merge = require('webpack-merge');
const common = require('./webpack.base.js');
const path = require('path');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  devServer: { // 开发服务器
    // dev-server 服务路径
    contentBase: path.join(__dirname, "dist"),
    compress: true,
    host: '0.0.0.0',
    //host: 'localhost',
    port: 8085,
    // 自动打开浏览器
    open: true,
    // 启动热更新
    hot: true,
    // 显示 webpack 构建进度
    progress: true,

    
    //重载脚本出现在包中,构建消息会出现在控制台。
    inline: true,
    // 在页面上全屏输出报错信息
    overlay: {
      warnings: true,
      errors: true
    },
    clientLogLevel: 'warning',
    // 可以进行接口代理配置
    proxy: {
      "/api": {
        target: "http://erp.my012.com:8081",
        //https会用到
        secure: false
      }
    },
    publicPath: '/'

  },
  output: { // 输出
    filename: 'js/[name].[hash].js', // 每次保存 hash 都变化
    path: path.resolve(__dirname, '../dist')
  },
  module: {},
  plugins: [
    //命令行模式 --hot 将会自动添加此插件
    //new webpack.HotModuleReplacementPlugin()
  ]
});

webpack.prod.js

// webpack.prod.js
// 存放 prod 配置
const path = require('path');
// 合并配置文件
const merge = require('webpack-merge');
const common = require('./webpack.base.js');
// 打包之前清除文件
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 分离CSS插件
//const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 压缩CSS和JS代码
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
//const process.env.NODE_ENV = 'production'


module.exports = merge(common, {
  module: {},
  /*
  webpack 执行模式
  development:开发环境,它会在配置文件中插入调试相关的选项,比如 moduleId 使用文件路径方便调试
  production:生产环境,webpack 会将代码做压缩等优化
  */
  mode: 'production',
  devtool: 'cheap-module-source-map',
  output: {
    filename: 'js/[name].[contenthash].js', //contenthash 若文件内容无变化,则contenthash 名称不变
    // 打包输出目录
    path: path.resolve(__dirname, '../dist')
  },
  plugins: [
    new CleanWebpackPlugin(['dist/*'], {
      root: path.resolve(__dirname, '../')
    })
    /* new MiniCssExtractPlugin({
      filename: "css/[name].[hash].css",
      chunkFilename: 'css/[id].[hash].css'
    }) */
  ],
  //分离不常变化的文件, 如 node_modules 下引用的库---webpack中的字段
  optimization: {
    // 分离chunks
    splitChunks: {
      /*
      默认 entry 的 chunk 不会被拆分
      因为我们使用了 html-webpack-plugin 来动态插入 <script> 标签,entry 被拆成多个 chunk 也能自动被插入到 html 中,
      所以我们可以配置成 all, 把 entry chunk 也拆分了
      */
      chunks: 'all',
      cacheGroups: {
        common:{
          /* chunks: "initial",
          minChunks: 2,
          maxInitialRequests: 5,
          minSize: 10000 */
        },
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          chunks: "initial", // 只打包初始时依赖的第三方
          name: "vendor",
          priority: 10
          //enforce: true   //
        },
        styles: {
          /* name: 'style',
          test: /\.(sa|sc|c)ss$/,
          chunks: 'all',
          enforce: true */
        }
      }
    },
    /* runtimeChunk: {
      name: "manifest"
    }, */
    minimizer: [
      // 压缩JS-- 自定义js优化配置,将会覆盖默认配置
      new UglifyJsPlugin({
        exclude: /\.min\.js$/, // 过滤掉以".min.js"结尾的文件,我们认为这个后缀本身就是已经压缩好的代码,没必要进行二次压缩
        uglifyOptions: {
          compress: {
            warnings: true, // 去除警告
            drop_debugger: true, // 去除debugger
            drop_console: true // 去除console.log
          }
        },
        cache: true, // 开启缓存
        parallel: true, // 平行压缩,开启并行压缩,充分利用cpu
        sourceMap: false,  // set to true if you want JS source maps
        extractComments: true // 移除注释
      }),
      // 压缩css
      new OptimizeCSSAssetsPlugin({})
    ]

  }

});

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

推荐阅读更多精彩内容