Logan 如果前面还有路,答应我,跑下去...

学习webpack4

2018-05-04
Logan

一、Webpack介绍

webpack是什么

  • webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。

webpack的作用

  • 打包(把多个文件打包成一个js文件,减少服务器压力、带宽)
  • 转化(less/sass/ts)需要loader
  • 优化(SPA越来越盛行,前段项目复杂度高,webpack可以对项目进行优化)

webpack的构成

  • entry 入口
  • output 出口
  • module 模块
  • plugins 插件
  • devSever 开发服务器
  • mode 开发模式 development/production

相关知识

低级错误

module.exports误写为module.export,导致打包时报错

path.join()path.resolve()的区别

pathnode.js的内置模块,提供了一些工具函数,用于处理文件与目录的路径。

__dirname:获得当前执行文件所在目录的完整目录名,即绝对路径

path.join()

  • path.join() 方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。
  • 可以理解为path.join()是将各个path片段连接在一起,即进行字符串拼接,但是遇到..还是会解析
path.join('/foo', 'bar', 'baz/asdf', 'quux');
// 返回: '/foo/bar/baz/asdf/quux'

path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'

path.resolve()

  • path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。
  • path.resolve()会将/xxx解析为绝对路径
  • path.resolve()将参数从右往左解析,直到构造完成一个绝对路径。
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'

path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'

npx 简介

npx 是跟随 npm@5.2.0 发布的,npm 5.2.0 以上版本中内置npx

npx是npm内置的包执行器,类似于 npm 简化了项目开发中的依赖安装与管理

之前我们可能会写这样的命令:

npm i -D webpack
./node_modules/.bin/webpack -v

有了 npx,你只需要这样

npx webpack -v

npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到, 就会帮你安装, 这里的PATH 就是项目 node_modules

如果npm版本较低,可以全局安装 npm install -g npx

直接运行远端脚本

npx 甚至支持运行远程仓库的可执行文件

$ npx github:piuccio/cowsay hello

二、Webpack的安装及初始化

mkdir webpack4
cd webpack4
npm init -y

npm i webpack webpack-cli webpack-dev-server -D  // 安装webpack


mkdir src

New-Item webpack.config.js

三、package.json配置

...
"scripts": {
  "dev": "npx webpack-dev-server  --mode=development  --hot --open", // 开发环境
  "build": "npx webpack --mode=production" // 生产环境
},
...

四、webpack.dev.js初步配置

const path = require('path')
module.exports = {
  // 入口:有且可以有多个,数组形式
  entry: {
    main: ['./src/index.js']
  },
  // 打包环境:开发 & 生产
  // mode: 'development',
  // 出口:有且只能有一个
  output: {
    filename: '[name].[hash:8].js',
    path: path.resolve(__dirname, '../dist'),
    publicPath: '/', //公共文件生成的地址
    chunkFilename : '[name].chunk.js' //公共块生成的文件根据入口文件名字生成
  },
  // 本地服务器配置
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),//开启devserver后默认进入dist/index.html
    overlay: true,  // 全屏遮罩显示编译器错误或警告
  }
}

五、处理JS文件

1. 安装babel

处理js文件我们需要用到babel,先安装一下

npm i babel-loader babel-core -D

2. 安装 babel-preset-envbabel-preset-stage-0

npm i babel-preset-env babel-preset-stage-0 -D

babel-preset-env介绍

babel-preset-env能根据当前的运行环境,自动确定你需要的 plugins 和 polyfills。

{
  "presets": [
    [
      "env",
      {
        "targets": { // 配支持的环境
          "browsers": [ // 浏览器
            "last 2 versions",
            "safari >= 7"
          ],
          "node": "current" // 通过Babel编译你的Node.js代码,支持的是当前运行版本的nodejs
        },
        "modules": true,
        "debug": true,
        "useBuiltIns": false,
        "include": [],
        "exclude": []
      }
    ]
  ],
  plugins: []
}
  • target.browsers: 指定相应的浏览器配置
      // 例子
      "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
    
  • target.node: 如果你通过Babel编译你的Node.js代码,targets.node: "current",支持的是当前运行版本的nodejs
  • modules: 将ES6语法转换为另一种模块模型 可选值:”amd”、 “commonjs”、 “systemjs”、 “umd” 设置为false则禁止转译模块语法

    webpack已经把这个事情做了,所以就不需要babel来做了,但是babel配置项中的modules默认值是commonjs,所以你需要将modules设置为false才行,不然就冲突了。

  • include: 必须要转译的功能,跟单独启用相应插件是一样的。
  • exclude: 禁止转译的功能
  • useBuiltIns:默认值: false。设置为true可以实现babel-preset-env基于特定环境引入需要的polyfill。
      // 使用方法
      npm i babel-polyfill // 安装 polyfill
      import 'babel-polyfill // 在入口js处引入
    

    最终都会根据环境转译成特定的polyfill。 比如:

      require('core-js/modules/es6.typed.array-buffer');
      require('core-js/modules/es6.typed.int8-array');
    

    在整个应用里只能引入一次polyfill,可以在 index.js 里一次引入。
    useBuiltIns 会使浏览器下载的代码变少 (最终打包的文件大小变小了)。但是不会节约内存, 因为polyfill本身只会安装缺少的部分。

  • debug: 默认为false,设置为true则console.log输出目标环境、启用的transforms、启用的plugins、启用的polyfills

babel-preset-stage-0是对 ES7 支持的插件

3. 浏览器兼容及性能问题

为防止浏览器不支持 Promise/Object.assign/Array.from等还有性能问题,我们引入babel-polyfillbabel-plugin-transform-runtime:

npm i babel-polyfill babel-runtime -S
npm i babel-plugin-transform-runtime -D

在入口文件引入babel-polyfill

import 'babel-polyfill'

4. 配置.babelrc

在根目录下创建.babelrc

{
  "presets": [
    ["env", {
      "modules": false, // 设置为false禁止转译模块语法
      "debug": true,// 开启debug模式,编译时会显示配置的信息
      "targets": {
        // 配置浏览器支持信息
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 
      },
      "useBuiltIns": true // 引入需要的polyfill而不是全部
    }],
    "stage-0" // es7支持
  ],
  "plugins": ["transform-runtime"]
}

5. 配置加载器(loader)

// js loader
{
  test: /\.js$/,
  use: [
    {
      loader: 'babel-loader',
      include: path.resolve(__dirname , 'src'),
      exclude: /node_modules/
    }
  ]
}

六、处理CSS文件

1. 安装处理CSS相关loader

npm i css-loader style-loader -D
  • css-loader: 能让你import css
  • style-loader: 能将css以style的形式插入

2. 安装postcssautoprefixer添加浏览器前缀(或者postcss-cssnext)

npm i postcss-loader autoprefixer -D
//第二种方法
npm i postcss-loader postcss-cssnext  -D

创建postcss.config.js,加入以下代码

module.exports = {
  plugins: [
    require('autoprefixer')()
  ]
}
// 第二种方法
module.exports = {
  plugins: [
    'postcss-cssnext': {}
  ]
}

4. 安装生成单独CSS插件和热更新loader

npm i mini-css-extract-plugin css-hot-loader -D
// npm i extract-text-webpack-plugin@next -D
// 注意extract-text-webpack-plugin 必须下载next版本 不然不支持webpack4

5. 配置加载器(loader)和插件(plugins)

// const ExtractTextWebapckPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
...
// css loader
{
  test: /\.css$/,
  use: [
    'css-hot-loader',
    MiniCssExtractPlugin.loader,
    'css-loader',
    'postcss-loader'
  ]
  // use: ExtractTextWebapckPlugin.extract({
  //   use: ['css-loader','postcss-loader']
  // })
},
...
plugins:[
  ...
  new MiniCssExtractPlugin({
    filename:'style.[hash:8].css'
  })
]

6. 在src/index.jsCSS

require('./style.css')
...

七、处理HTML文件(方法一,推荐)

1. 安装插件

npm i html-webpack-plugin -D

2. 配置插件(plugins)

const HtmlWebpackPlugin = require('html-webpack-plugin');
...
plugins:[
  new HtmlWebpackPlugin({
    template: path.resolve(__dirname,'src','index.html'),//模板
    filename:'index.html', // 文件名
    hash:true,//防止缓存
    minify:{
      removeAttributeQuotes:true//压缩 去掉引号
    }
  }),
]

八、处理HTML文件(方法二,不推荐)

1. 在src/index.js内引入html

require('./index.html')
...

2. 安装相关加载器(loader)

npm i file-loader extract-loader html-loader -D

3. 配置加载器(loader)

// html loaders
{
  test: /\.html$/,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: '[name].[ext]'
      }
    },
    {
      loader: 'extract-loader'
    },
    {
      loader: 'html-loader',
      options: {
        attrs: ["img: src"]            // 配置加载图片
      }
    }
  ]
}

九、处理图片

1. 常见的三种加载图片的方式

  • css中引入
#wrapper {
  background-image: url('./image/1.jpg);
}
  • js动态引入
let imgSrc = require('./images/1.png');
let img = new Image();
img.src = imgSrc;
document.getElementById('root').appendChild(img);
  • html img 标签
<img src="./image/1.jpg" alt="">

2. 前两种加载方式的处理

npm i file-loader url-loader -D
...
{
  test:/\.(jpg|png|gif|svg)$/,
  use:'url-loader?limit=8192&name=[name].[hash:8].[ext]&outputPath=images/',
  include:path.join(__dirname,'./src'),
  exclude:/node_modules/
}

3. 第三种加载方式的处理

使用html-loader进行处理

npm i html-loader -D
...
{
  test: /\.(htm|html)$/,
  use: 'html-loader'
}

十、清理打包文件的插件

安装插件

npm i clean-webpack-plugin -D

配置插件

const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
  ...
  new CleanWebpackPlugin(['dist'])
]

十一、实现热更新

devServer: {
  // ...
  hot: true,
  open: true
},
plugins: [
  // ...
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
]

十二、多入口程序构建

需求:如何让对应的入口文件的html模版文件,引入只与本模块有关的js/css 。

1、在entry添加对应的模块入口

entry:{//入口文件
  pagea:'./src/pagea/index.js', 
  pageb:'./src/pageb/index.js'
}

2、如何让对应的入口文件的html,引入只与本模块有关的js

通过 html-webpack-plugin 解决。首先配置多个 html-webpack-plugin 实例对象,然后指定每个实例对象需要引入的 chunks 文件即可。

new HtmlWebpackPlugin({
  template: path.resolve(__dirname,'src','index.html'),//模板
  filename:'pagea.html',
  chunks:['pagea'],
  minify:{
    removeAttributeQuotes:true//压缩 去掉引号
  }
}),
new HtmlWebpackPlugin({
  template: path.resolve(__dirname,'src','index.html'),//模板
  filename:'pageb.html',
  chunks:['pageb'],
  minify:{
    removeAttributeQuotes:true//压缩 去掉引号
  }
})

当需要引入多个的时候只需要在数组里面添加对应的模块名称即可。


下一篇 Mac配置

留言

目录