使用webpack4打造本身的前端工做流

前言

webpack4发布已经有一段时间了,我在实践的过程当中发现,不少项目配置在webpack3下工做正常,可是升级到webpack4直接就崩了,若是想要webpack4正常工做,不少插件也须要升级到新版。下面是我使用webpack4配置的一个学习案例,包含了平常开发的经常使用配置项,好比多入口文件配置、模板文件自定义、版本号控制、js和css分离、css自动添加前缀、scss转css、图片及字体文件的处理、babel编译JS语法和API等等javascript

版本号

当咱们修改代码后,须要从新打包文件,这时候为了不浏览器缓存,每每须要为文件添加一个版本号css

var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject:'body', // 插入位置
      favicon: './favicon.ico', // icon图标
      title: 'webpack learn', // 生成的html文件的标题
      filename: 'index.html', // 生成的html文件名称
      minify:{
        removeComments: false, // 删除注释
        collapseWhitespace: false // 删除空格
      }
    })
  ]
}
复制代码

打包后的代码html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack learn</title>
    <link rel="shortcut icon" href="favicon.ico">
  </head>
  <body>
  <script type="text/javascript" src="main.js?f8f60ca3f6ee44382620"></script></body>
</html>
复制代码

html-webpack-plugin这个插件会生成一个名为index.html、标题是webpack learn的文件,而且自动把打包后的文件插入到html中。若是不配置这个插件,filename的默认值就是index.html,title默认是Webpack APPjava

inject表示插入的位置,默认是body,可选值head favicon表示能够添加一个icon图标 minify表示对压缩文件,removeComments和collapseWhitespace的默认值都是falsenode

模板文件

html-webpack-plugin插件可使用模板文件,这样咱们就能够自定义一个html文件,而后让这个插件把打包后的文件自动插入到模板文件中jquery

tmp/tmp.html模板文件webpack

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>template file</title>
  <body>
  <div>hello template</div>
</html>
复制代码

插件配置项git

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: './tmp/tmp.html'
  })
]
复制代码

打包后生成的index.htmlgithub

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>template file</title>
  <body>
  <div>hello template</div>
</html>
<script type="text/javascript" src="main.js?b321307e65d6b0fbee0b"></script>
复制代码

多页面

对于多页面通常会对应多个入口文件,不一样的html页面输出对应不一样的入口文件,html-webpack-plugin插件支持配置多页面。多页面须要配置chunks和excludeChunks,chunks表示所包含的入口文件,excludeChunks表示要排除的入口文件web

var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    a: './src/main-a.js',
    b: './src/main-b.js',
    c: './src/main-c.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'a.html',
      template: './tmp/tmp.html',
      chunks: ['a'] // 加载a对应的打包文件
    }),
    new HtmlWebpackPlugin({
      filename: 'b.html',
      template: './tmp/tmp.html',
      chunks: ['b']  // // 加载b对应的打包文件
    }),
    new HtmlWebpackPlugin({
      filename: 'c.html',
      template: './tmp/tmp.html',
      excludeChunks: ['a', 'b'] // 加载非a、b对应的打包文件
    })
  ]
}
复制代码

运行结果

<!-- a.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack learn</title>
  <body>
  <div>hello template</div>
</html>
<script type="text/javascript" src="a.js?82a9a04389852053c167"></script>

<!-- b.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack learn</title>
  <body>
  <div>hello template</div>
</html>
<script type="text/javascript" src="b.js?82a9a04389852053c167"></script>

<!-- c.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack learn</title>
  <body>
  <div>hello template</div>
</html>
<script type="text/javascript" src="c.js?82a9a04389852053c167"></script>
复制代码

内联

除了以连接的形式引入入口文件,也能够内联到页面中。html-webpack-inline-source-plugin插件专门用来处理入口文件内联的

var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  plugins: [
    new HtmlWebpackPlugin({
      inlineSource: '.(js|css)$' // 全部的js和css文件内联引入
    }),
    new HtmlWebpackInlineSourcePlugin()
  ]
}
复制代码

babel

babel能够把es最新标准的代码转为es5代码,首先须要安装babel-core核心程序,及babel-loader

npm i babel-loader babel-core -D
复制代码

因为ES每一年会发布一个新版本,因此在进行转换时,须要选择从哪一个标准进行转换,可供选择的有'es2015'、'es2016'、'es2017'、'latest'、'env'等多个不一样的标准。

babel-preset-env标准是使用最多的,babel-preset-env在没有任何配置选项的状况下,与 babel-preset-latest(或者babel-preset-es2015,babel-preset-es2016和babel-preset-es2017一块儿)的行为彻底相同

npm i babel-preset-env  -D
复制代码
var webpack = require('webpack');
var path = require('path');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  module: {
    rules:[{
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env'],
          cacheDirectory: true
        }
      }
    }]
  }
}
复制代码

rules属性中配置的exclude表示node_modules文件夹不须要babel进行转换。也能够配置一个include选项,好比include: path.resolve(__dirname, 'src'),表示只有src文件夹中的文件须要转换

cacheDirectory选项的默认值是false,设置为true将缓存 loader 的执行结果,加快编译速度

API转换

babel默认只转换JavaScript语法,对于新的API,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等是不会转换的。若是须要转换API,须要使用babel-polyfill,babel-polyfill是一个全局垫片

npm i babel-polyfill -D
复制代码

入口文件引入babel-polyfill

// main.js
import 'babel-polyfill';
let set = new Set([1,2,3]);
复制代码

babel-polyfill是一个全局垫片,开发中更经常使用的是babel-plugin-transform-runtime这个局部垫片,由于它可使包的体积更小

npm i babel-plugin-transform-runtime babel-runtime -D
复制代码
var webpack = require('webpack');
var path = require('path');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  module: {
    rules:[{
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env'],
          cacheDirectory: true,
          plugins: ['transform-runtime']
        }
      }
    }]
  }
}
复制代码

CSS

处理css会用到css-loader和style-loader,css-loader用于读取并加载css文件,style-loader将它插入到页面中

// main.js
require('./assets/styles/cssdemo.css');
复制代码
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  module: {
    rules:[{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}
复制代码

自动前缀

因为各大浏览器对CSS兼容性不一样,部分CSS特性须要加上浏览器前缀才能正常工做,postcss-loader能够帮咱们自动完成加前缀的工做

npm i postcss-loader autoprefixer postcss-import -D
复制代码
module: {
  rules: [{
    test: /\.css$/,
    use: ['style-loader', {
        loader: 'css-loader',
        options: { importLoaders: 1 }
      },
      {
        loader: 'postcss-loader',
        options: {
          plugins: [
            require('postcss-import'), // 解决css中import其余css
            require('autoprefixer')
          ]
        }
      }
    ]
  }]
}
复制代码

sass

须要安装sass-loader及node-sass。

npm i sass-loader node-sass -D
复制代码
module: {
  rules: [{
    test: /\.scss$/,
    use: ['style-loader','css-loader',
      {
        loader: 'postcss-loader',
        options: { plugins: [require('autoprefixer')] }
      },
      'sass-loader'
    ]
  }]
}
复制代码

分离css

默认状况下,CSS会被打包到入口JS文件中。若是须要把CSS分离出来,须要使用extract-text-webpack-plugin插件

npm i extract-text-webpack-plugin@next -D
复制代码
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js?[hash]'
  },
  module: {
    rules: [{
      test: /\.scss$/,
      use: ExtractTextPlugin.extract({
        fallback: 'style-loader',
        use: ['css-loader',
          {
            loader: 'postcss-loader',
            options: { plugins: [require('autoprefixer')] }
          },
          'sass-loader'
        ]
      })
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({}),
    new ExtractTextPlugin('main.css')
  ]
}
复制代码

图片资源

webpack处理图片、字体、音乐、视频等资源时,须要安装file-loader

npm i file-loader -D
复制代码
// main.js
require('./assets/styles/cssdemo.css');
复制代码
/* cssdemo.css */
body {
  background: url('../images/dog.jpg') no-repeat;
}
h1 {
  color: red;
}
复制代码
module: {
  rules: [{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }, {
      test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
      loader: 'file-loader'
    },
    {
      test: /\.(png|jpe?g|gif|svg)(\?\S*)?$/,
      loader: 'file-loader',
      query: {
        name: '[name].[ext]?[hash]'
      }
    }
  ]
}
复制代码

若是是在html模板中,经过img标签引入图片,须要使用${require('')}将相对路径包裹一次

<img src="${require('../src/images/dog.jpg')}" alt="">
复制代码

第三方库

好比说咱们经过npm安装了jQuery,只须要经过provide-plugin插件就能够自动加载模块,而没必要处处 import 或 require

npm i provide-plugin -D
复制代码
var ProvidePlugin = require('provide-plugin');

plugins: [
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery'
  })
]
复制代码

在项目中使用

console.log($('#box'), jQuery('#box'))
复制代码

若是是把jQuery保存到了本地,能够经过设置别名来引用

resolve:{
  alias:{
    jQuery$: path.resolve(__dirname,'src/libs/jquery.min.js')
  }
}
复制代码

实用配置

最后基于上面的全部介绍,把全部的配置综合到一块儿。因为代码比较多,就再也不这里展开了,我把示例代码放到了GitHub

webpack-demo

Blog

参考文章

Babel 入门教程

webpack实用配置

babel-preset-env使用方法

相关文章
相关标签/搜索