webpack4入门篇

一.安装步骤

1.新建项目webpack-democss

2.安装webpackhtml

npm install webpack webpack-cli -gvue

3.项目初始化node

npm init -y //-y默认全部的配置webpack

安装依赖环境es6

npm i webpack webpack-cli -Dweb

//-D webpack安装在devDependencies环境中正则表达式

二.部署webpack

1.package.json里配置咱们的scriptsvuex

{
  "name": "webpack_demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode production"
    //咱们在这里配置,就可使用npm run build 打包咱们的项目 像使用vue-cli脚手架那样
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.8"
  }
}
复制代码

三.配置流程

1.Html在webpack中的配置

新建webpack.config.js文件 新建index.html文件vue-cli

必须都在根目录下面 webpack默认找根目录下的配置

配置咱们的入口entry,在vue-cli里至关于跟目录下的main.js,咱们的出口output。咱们能够把webpack理解为一个工厂,进入至关于把各类各样的原料放进咱们的工厂了,而后工厂进行一系列的打包操做把打包好的东西,向外输出,而后就能够去出售了(上线)。

html-webpack-plugin

插件来将 HTML 引用路径和咱们的构建结果关联起来。 npm run buid 以后 dist 目录就会多个 index.html 并引入了 main.js.

new HtmlWebpackPlugin({
  title: 'webpack-demo',//标题
  filename: 'index.html', // 配置输出文件名和路径
  template: './index.html', // 配置要被编译的html文件
  inject: true,//script标签位于html文件的body底部 true/body/head/false 默认true
  favicon: './src/assets/img/logo.png',//指定页面图标 而后在生成的html中就有一个link标签:<link rel='shortcut icon' href='example.ico'>
  // 压缩 => production 模式使用
  //生产为true 其余的时候为false
  minify: {
    caseSensitive:false,//是否大小写敏感 默认flase
    removeAttributeQuotes: true, //去掉属性引用 删除双引号 默认false
    collapseWhitespace: true, //是否去除空格 折叠 html 为一行 默认false
    removeComments:true//去注释 默认false
  },
  hash: true,//是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦。默认为false。
  cache: true,//默认是true的,表示内容变化的时候生成一个新的文件。
  showErrors: true,//是否将错误信息写在页面里,默认true,出现错误信息则会包裹在一个pre标签内添加到页面上。
  chunks:'' //引入的模块,这里指定的是entry中设置多个js时,在这里指定引入的js,若是不设置则默认所有引入。
  chunksSortMode: '' //这个选项决定了 script 标签的引用顺序。默认有四个选项,'none' | 'auto' | 'dependency' | 'manual' | {Function}
    - none: 无序
    - auto: 默认值, 按插件内置的排序方式
    - dependency: 根据不一样文件的依赖关系排序(通常用于生产)
    - manual: chunks按引入的顺序排序, 即属性chunks的顺序
    - {Function}: 指定具体的排序规则
})
复制代码

2.css在webpack中的配置

咱们但愿使用 webpack 来进行构建 css 文件,为此,须要在配置中引入 loader 来解析和处理 CSS 文件:

npm install style-loader css-loader -D

在src的assets里面的css文件中新增color.css添加样式,在index.js中引入这个css import './assets/css/color.css'

在webpack.config.js中配置loader

module: {
    /**
     * test: 匹配特定条件。通常是提供一个正则表达式或正则表达式的数组
     * include: 匹配特定条件。通常是提供一个字符串或者字符串数组
     * exclude: 排除特定条件
     * and: 必须匹配数组中的全部条件
     * or: 匹配数组中任何一个条件,
     * nor: 必须排除这个条件
     */
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, 'src')],
        use: ['style-loader', 'css-loader']
      }
    ]
 }
复制代码

经由上述两个 loader 的处理后,CSS 代码会转变为 JS, 若是须要单独把 CSS 文件分离出来,咱们须要使用 mini-css-extract-plugin 插件

抽取 css 到独立文件, 自动添加前缀

npm i mini-css-extract-plugin postcss-loader autoprefixer -D

咱们在写 css 时难免要考虑到浏览器兼容问题,如 transform 属性,须要添加浏览器前缀以适配其余浏览器。故使用到 postcss-loader 这个 loader, 下面则是相关的配置

注意: 若是浏览器前缀添加不成功,记得要在autoprefixer后面加("last 100 versions")

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production';

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, 'src')],
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
	          publicPath: '../',//为了防止css里面有引用背景图片 图片打包以后在dist/images路径错误问题
              hmr: devMode, // 仅dev环境启用HMR功能
            }
          },
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')("last 100 versions")]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    //...
    new MiniCssExtractPlugin({
      // 这里的配置和webpackOptions.output中的配置类似
      // 便可以经过在名字前加路径,来决定打包后的文件存在的路径
      filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
      chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
    })
  ]
}
复制代码

3.图片资源在webpack中的配置

npm install file-loader url-loader -D

file-loader: 能够用于处理不少类型的文件,它的主要做用是直接输出文件,把构建后的文件路径返回。

url-loader: 若是图片较多,会发不少 http 请求,会下降页面性能。url-loader 会将引入的图片编码,生成 dataURl。至关于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只须要引入这个文件就能访问图片了。固然,若是图片较大,编码会消耗性能。所以 url-loader 提供了一个 limit 参数,小于 limit 字节的文件会被转为 DataURl,大于 limit 的还会使用 file-loader 进行 copy。

  • url-loader 能够看做是加强版的 file-loader。
  • url-loader 把图片编码成 base64 格式写进页面,从而减小服务器请求。

配置以下:

module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              outputPath: 'images/', //输出到images文件夹
              limit: 10000, //是把小于6000B的文件打成Base64的格式,写入JS
              name: "[name]-[hash:5].min.[ext]",
            }
          }
        ]
      }
    ]
  }
  //...
}
复制代码

4.js在webpack中的配置

如今随着es6的普及,愈来愈多的代码使用es6了,可是不少浏览器并不支持es6,好比async/awiat,const。所以须要咱们引用babe来把咱们es6的代码编译为es5。在跟目录下新建.babelrc,简单配置下

{"presets": ["env"]}

安装所需依赖:npm i babel-loader babel-core babel-preset-env -D

{
   test: /\.js$/,  //es6 => es5
   exclude: /node_modules/,
   use: 'babel-loader'     
}
复制代码

报错:Error: Cannot find module '@babel/core' babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7' 由于babel-loader的版本问题

先卸载 npm uninstall babel-loader 重装一个@7的版本 npm i babel-loader@7 -D

四:打包前清理源目录文件 clean-webpack-plugin

npm install clean-webpack-plugin -D

配置以下:

const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
  plugins: [
  	new CleanWebpackPlugin(['dist'])
  ]
}
复制代码

报错:TypeError: CleanWebpackPlugin is not a constructor 修改引用方式:const {CleanWebpackPlugin} = require('clean-webpack-plugin');

又报错:Error: clean-webpack-plugin only accepts an options object 修改调用方式,不传入目录:new CleanWebpackPlugin()

五:提取公用代码

假如你 a.js 和 b.js 都 import 了 c.js 文件,这段代码就冗杂了。为何要提取公共代码,简单来讲,就是减小代码冗余,提升加载速度。

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          // 抽离本身写的公共代码
          chunks: 'initial',
          name: 'common', // 打包后的文件名,任意命名
          minChunks: 2, //最小引用2次
          minSize: 0 // 只要超出0字节就生成一个新包
        },
        styles: {
          name: 'styles', // 抽离公用样式
          test: /\.css$/,
          chunks: 'all',
          minChunks: 2,
          enforce: true
        },
        vendor: {
          // 抽离第三方插件
          test: /node_modules/, // 指定是node_modules下的第三方包
          chunks: 'initial',
          name: 'vendor', // 打包后的文件名,任意命名
          // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
          priority: 10
        }
      }
    }
  }
}
复制代码

六:hash

hash 是干吗用的? 咱们每次打包出来的结果可能都是同一个文件,那我上线的时候是否是要替换掉上线的 js,那我怎么知道哪是最新的呢,咱们通常会清一下缓存。而 hash 就是为了解决这个问题而存在的

module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:8].js'
  },
  //...
  plugins: [
    new MiniCssExtractPlugin({
      filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
  chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
    })
  ]
}
复制代码

七:减小 resolve 的解析,配置别名

若是咱们能够精简 resolve 配置,让 webpack 在查询模块路径时尽量快速地定位到须要的模块,不作额外的查询工做,那么 webpack 的构建速度也会快一些

module.exports = {
  resolve: {
    /**
     * alias: 别名的配置
     *
     * extensions: 自动解析肯定的扩展,
     *    好比 import 'xxx/theme.css' 能够在extensions 中添加 '.css', 引入方式则为 import 'xxx/theme'
     *    @default ['.wasm', '.mjs', '.js', '.json']
     *
     * modules 告诉 webpack 解析模块时应该搜索的目录
     *   若是你想要添加一个目录到模块搜索目录,此目录优先于 node_modules/ 搜索
     *   这样配置在某种程度上能够简化模块的查找,提高构建速度 @default node_modules 优先
     */
    extensions: ['.vue', '.js', '.json','.css'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',      
      '@':
        path.resolve(__dirname, 'src'),
      '@components':
        path.resolve(__dirname, 'src/components/'),
      '@assets':
        path.resolve(__dirname, 'src/assets'),
    },
    modules: [path.resolve(__dirname, 'src'), 'node_modules']
  }
}
复制代码

八:webpack-dev-serve

安装:npm install webpack-dev-server -D package.json 中 scripts 中添加:"dev": "webpack-dev-server --mode development"

devServer: {
    host: '0.0.0.0',//主机名
    port: 8080,//端口
    open: true,//自动打开浏览器
    compress: true,//服务器压缩
    hot:true,//热更新
    inline:true,//页面自动刷新
    //跨域问题
    proxy:{
      '/api': {
        target: 'https://testbi.promni.cn/v2/api',
        secure: false,
        changeOrigin: true,
        pathRewrite: {'^/api' : ''}
      }
    },
  },
复制代码

九:模块热替换(hot module replacement)

模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程当中替换、添加或删除模块,而无需从新加载整个页面。主要是经过如下几种方式,来显著加快开发速度:

保留在彻底从新加载页面时丢失的应用程序状态。 只更新变动内容,以节省宝贵的开发时间。 调整样式更加快速 - 几乎至关于在浏览器调试器中更改样式。

上面咱们 npm start 后修改一次文件,页面就会刷新一次。这样就存在很大问题了,好比咱们使用 redux, vuex 等插件,页面一刷新那么存放在 redux, vuex 中的东西就会丢失,很是不利于咱们的开发。

import webpack from 'webpack';
plugins: [
   new webpack.HotModuleReplacementPlugin()
    //...
]
配置后还不行,由于 webpack 还不知道你要更新哪里, 修改 src/index.js 文件, 添加
if (module.hot) {
  module.hot.accept()
}
复制代码

可是可是有个问题是,你修改 css/less 等样式文件并未发生改变, what ? HMR 修改样式表 须要借助于 style-loader, 而咱们以前用的是 MiniCssExtractPlugin.loader, 这也好办,修改其中一个 rules 就能够了,咱们能够试试改

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          // MiniCssExtractPlugin.loader,
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')] // 添加css中的浏览器前缀
            }
          },
          'less-loader'
        ]
      }
    ]
  }
}
复制代码

咱们能够发现,dev 下配置的 loader 为 style-loader , 而生产环境下则是须要 MiniCssExtractPlugin.loader 这就涉及到了不一样环境之间的配置。能够经过 process.env.NODE_ENV 获取当前是开发环境或者是生产环境,而后配置不一样的 loader,这里就不作展开了

十:完整webpack代码

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  //打包入口
  entry: {
    main: './src/index.js',
    page1: "./src/assets/js/page1.js",//测试提取公用代码
    page2: "./src/assets/js/page2.js",//测试提取公用代码
  },
  //打包出口
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:8].js'
  },
  module: {
    /**
     * test: 匹配特定条件。通常是提供一个正则表达式或正则表达式的数组
     * include: 匹配特定条件。通常是提供一个字符串或者字符串数组
     * exclude: 排除特定条件
     * and: 必须匹配数组中的全部条件
     * or: 匹配数组中任何一个条件,
     * nor: 必须排除这个条件
     */
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, 'src')],
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',//为了防止css里面有引用背景图片 图片打包以后在dist/images路径错误问题
              hmr: devMode, // 仅dev环境启用HMR功能
            }
          },
          // 'style-loader', 模块热替换时候用的
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')("last 100 versions")]//添加浏览器前缀
            }
          }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              outputPath: 'images/', //输出到images文件夹
              limit: 6000, //是把小于6000B的文件打成Base64的格式,写入JS
              name: "[name]-[hash:5].min.[ext]",
            }
          }
        ]
      },
      {
        test: /\.js$/,  //es6 => es5
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'webpack-demo',//标题
      filename: 'index.html', // 配置输出文件名和路径
      template: './index.html', // 配置要被编译的html文件
      favicon: './src/assets/img/logo.png',//指定页面图标 而后在生成的html中就有一个link标签:<link rel='shortcut icon' href='example.ico'>
      // 压缩 => production 模式使用
      minify: {
        removeAttributeQuotes: true, //去掉属性引用 删除双引号
        collapseWhitespace: true, //是否去除空格 折叠 html 为一行
        removeComments: true//去注释
      },
      hash: true,//是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦。默认为true。
    }),
    new MiniCssExtractPlugin({
      // 这里的配置和webpackOptions.output中的配置类似
      // 便可以经过在名字前加路径,来决定打包后的文件存在的路径
      filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
      chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
    }),
    //清理源目录文件
    new CleanWebpackPlugin(),
    //模块热替换
    new webpack.HotModuleReplacementPlugin()
  ],
  optimization: {
    //压缩文件 mode:production 生产环境配置
    minimizer: [
      new OptimizeCssAssetsWebpackPlugin(),// 压缩css
      new UglifyJsPlugin()//压缩js
    ],
    //提取公用代码
    splitChunks: {
      cacheGroups: {
        commons: {
          // 抽离本身写的公共代码
          chunks: 'initial',
          name: 'common', // 打包后的文件名,任意命名
          minChunks: 2, //最小引用2次
          minSize: 0 // 只要超出0字节就生成一个新包
        },
        styles: {
          name: 'styles', // 抽离公用样式
          test: /\.css$/,
          chunks: 'all',
          minChunks: 2,
          enforce: true
        },
        vendor: {
          // 抽离第三方插件
          test: /node_modules/, // 指定是node_modules下的第三方包
          chunks: 'initial',
          name: 'vendor', // 打包后的文件名,任意命名
          // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
          priority: 10
        }
      }
    }
  },
  // 减小 resolve 的解析,配置别名
  resolve: {
    extensions: ['.vue', '.js', '.json', '.css'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@':
        path.resolve(__dirname, 'src'),
      '@components':
        path.resolve(__dirname, 'src/components/'),
      '@assets':
        path.resolve(__dirname, 'src/assets'),
    },
  },
  //webpack-dev-server mode:development 开发环境配置
  devServer: {
    host: '0.0.0.0',//主机名
    port: 8080,//端口
    open: true,//自动打开浏览器
    compress: true,//服务器压缩
    hot: true,//热更新
    inline: true,//页面自动刷新
    //跨域问题
    proxy: {
      '/api': {
        target: 'https://testbi.promni.cn/v2/api',
        secure: false,
        changeOrigin: true,
        pathRewrite: {'^/api': ''}
      }
    },
  },

};
复制代码
相关文章
相关标签/搜索