zoukankan      html  css  js  c++  java
  • 使用webpack4打造自己的前端工作流

    前言

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

    版本号

    当我们修改代码后,需要重新打包文件,这时候为了避免浏览器缓存,往往需要为文件添加一个版本号

    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 // 删除空格
          }
        })
      ]
    }
    

    打包后的代码

    <!DOCTYPE html>
    <html>
      <head>
        
        <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 APP

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

    模板文件

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

    tmp/tmp.html模板文件

    <!DOCTYPE html>
    <html>
      <head>
        
        <title>template file</title>
      <body>
      <div>hello template</div>
    </html>
    

    插件配置项

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

    打包后生成的index.html

    <!DOCTYPE html>
    <html>
      <head>
        
        <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表示要排除的入口文件

    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>
        
        <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>
        
        <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>
        
        <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使用方法

  • 相关阅读:
    【转载】Java性能优化之JVM GC(垃圾回收机制)
    RobotFramework自动化测试框架-DatabaseLibrary库的使用(对数据库的操作)
    Linux性能分析工具top命令详解
    RobotFramework自动化测试框架-移动手机自动化测试Element Attribute Should Match关键字的使用
    RobotFramework自动化测试框架-移动手机自动化测试Get Network Connection Status和Set Network Connection Status关键字的使用
    RobotFramework自动化测试框架-移动手机自动化测试Get Element Location关键字的使用
    在linux下,怎么去查看一个运行中的程序, 到底是占用了多少内存
    RobotFramework自动化测试框架-移动手机自动化测试Click Element At Coordinates关键字的使用
    RobotFramework自动化测试框架-移动手机自动化测试Click A Point关键字的使用
    RobotFramework自动化测试框架-移动手机自动化测试Click Element关键字的使用
  • 原文地址:https://www.cnblogs.com/yesyes/p/15375790.html
Copyright © 2011-2022 走看看