webpack4简单入门

webpack4想使用命令行的话,需要安装webpack-cli,这个webpack-cli是在命令输入webpack 等指令操作的基础;可以加上npx即如:npx webpack 这样来调用

npx webpack <entry>

所以不影响的话,可以全局安装,这样就不需要每次都加上npx

npm install webpack-cli -g

或者说不要全局安装,直接装在项目里,然后配置package.jsonscript也可以

需要说的是在命令行使用webpack指令时,其实是在执行webpack.config.js里的配置,单独使用webpack时其实是执行了webpack.config.js文件,而webpack后面加上的指令,其实也是配置项,但是优先级高于webpack.config.js,如webpack -o 里的webpack.config.js也可以配置,但如果你给出这些配置的话,就会覆盖掉webpack.config.js里的配置

处理CSS

首先,webpack允许在入口文件直接引入其他不是js的文件,当然想要有作用还必须安装各种loader,如引入CSS文件,在入口js文件,可以直接这样写

/* style.css */
body {
  background-color: red;
}
/* index.js */
require('./style.css')

或者这样写,webpack同时支持直接使用ES6的模块化和Nodejs的模块化

/* index.js */
import './style.css'

webpack从入口文件就可以看到这个css文件,并且做出处理,当然如果没有loader就会报错,差不多如下

Module parse failed: Unexpected token (x:x)
You may need an appropriate loader to handle this file type, 
currently no loaders are configured to process this file.
See https://webpack.js.org/concepts#loaders

所以需要安装loader

npm install -D style-loader css-loader

webpack.config.js配置loader

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  }
}

注意,要想处理css文件,并成功把样式运用到页面上,需要这两个loader,缺一不可,webpack看到css文件后第一先交给css-loader处理,css-loader如果没有,只有style-loader的话也会报和上面同样的错误信息,因为没有东西可以接受这种文件,而style-loader是把css-loader处理后的样式应用到引用这个js文件html文件的style标签里,如下面index.html文件直接引用打包好的bundle.js文件,而如果没有style-loader的话,系统没有报错,但是样式是没有应用的!
webpack4简单入门_第1张图片

提取CSS

就是在打包的时候,把css抽取到一个独立的文件,而不是在bundle.js里。这里需要用到一个插件mini-css-extract-plugin,以下是它的地址

https://github.com/webpack-contrib/mini-css-extract-plugin

大概是这样用的,注意用的时候是取代style-loader或者vue-style-loader之类的最后应用型的loader,即css的loader处理链的最后一个(代码上看是第一个)

npm install -D mini-css-extract-plugin
let MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      /*
        {
           test: /\.css$/,
           use: ['style-loader', 'css-loader']
        },
     */
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      {
        test: /\.styl$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader']
      }
    ]
  },
  plugins: [new MiniCssExtractPlugin()]
}

但是这样子提取的css是没有被压缩的,如果想压缩需要安装优化插件

npm install -D optimize-css-assets-webpack-plugin

之后在配置文件配置

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
// .....
 optimization: {
    minimizer: [
      new OptimizeCSSAssetsPlugin({})
    ]
  },
 plugins: [
//........

这样生成的css就是被压缩的了

加载图片资源

webpack也可以处理静态资源,当你在入口文件导入图片时,webpack可以把这个图片导出到dist目录,这个功能需要使用file-loader

npm install file-loader -D 

webpack.config.js里,添加规则

{
  test: /\.(png|jpg|jpge|svg|gif)$/,
  use: [
    {
      loader: 'file-loader'
    }
  ]
}

例如在入口文件这样

import Logo from './logo.png'

我们打包后,在dist目录就会出现那个图片,但是图片的名称就不是上面的logo.png了,而是例如像65438e39703c520115768e7ebf0e31f3.png了,其实上面的那一串就是Logo的值。当你只使用了css-loader时,当你的css文件里有,如url()的值引入图片时,是会引入失败的,但当你有了file-loader后,配合css-loader它会在css里差不多像这样引入url(65438e39703c520115768e7ebf0e31f3.png)图片

压缩和优化图片

在有file-loader的基础上,可以用image-webpack-loader或者url-loader来进一步处理了

使用Babel

npm install @babel/core babel-loader @babel/preset-env -D

webpack.config.js里配置loader

module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: "babel-loader"
    }]
  }
}

在root目录下创建.babelrc配置文件,填入如下

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

之后项目打包时就可以转化为ES5了

开发服务器

其实就是用webpack-dev-serer,它会在本地打开一个端口,做为开发的静态服务器,而静态服务器的根路径就是dist目录,就是打包后bundle所在的目录,但是需要注意的是,这种方式打包的bundle是存在于内存里的,一旦服务关掉,打包的内容就会摧毁

npm install webpack-dev-server -D

webpack.config.js里对象的第一层加入下面属性

devServer: {
   contentBase: path.join(__dirname, './dist'),   // 指定静态目录
   port: 8848  // 指定端口
}

启动服务

webpack-dev-server --open

但是,webpack默认只认得js文件,就算打开了一个静态服务,里面的打包的内容也只有bundle.js,看不到页面效果的,所以需要一个index.html去引入bundle.js,所以,现在问题是怎么才可以让打包后的文件除了有bundle.js还有index.html,并且改HTML文件引入了bundle.js文件呢?
这时需要一个插件HtmlWebpackPlugin,简单使用如下

npm install html-webpack-plugin -D
// webpack.config.js
let HtmlWebpackPlugin = require('html-webpack-plugin')

// .....
 plugins: [
    new HtmlWebpackPlugin()
  ]
// .......

默认的话它会帮你创建以一个html文件,但是这个文件可能并不是你想要的,所以它也提供了一个接口,让你用自己的html模板

// .....
 plugins: [
    new HtmlWebpackPlugin({
	   template: path.join(__dirname, './public/index.html')
	})
  ]
// .......

关于HtmlWebpackPlugin怎么使用可以看https://webpack.docschina.org/plugins/html-webpack-plugin

这个时候,我们继续使用webpack-dev-server,在命令行使用

webpack-dev-server --open

打开浏览器,就可以看到页面效果了,并且,这个时候只要你修改了webpack依赖图的任何一个文件并保存后,不用手动刷新浏览器,它会自动刷新

注意:自动刷新并不是热替换,热替换甚至不需要刷新

SourceMap

sourcemap是用于帮助开发者发现bundel的BUG是由哪个原文件造成的,不用它的话,浏览器报错会直接报bundel的位置,这样的话你是很难知道找到问题的根源的,所以需要sourcemap。在webpack.config.js里配置devtool

module.exports = {
  mode: /*..........*/,
  entry: {/*..........*/},
  output: {/*..........*/},
  devtool: 'inline-source-map'
}

之后执行打包操作后,打包后的文件下方会出现类类似

/*# sourceMappingURL=data:application/json;charset=utf-8;base64.........*/

如果打包后的文件执行后有报错,会在控制台有报错误原位置,即打包前的位置

单位转换 px2rem

可以把css用到的所有px单位换成rem单位,只需要安装两个包

npm install -D px2rem px2rem-loader

webpack.config.js里面加入px2rem-loader

// ......
module: {
  rules: [
    {
      test: /\.css$/,
      use: [ 
        'style-loader',
        'css-loader',
        {
            loader: 'px2rem-loader',
            options: {
               remUnit: 75,
               remPrecision: 8
            }
         }
       ]
     }
  ]
}
// ......

配置项可以参考 https://github.com/songsiqi/px2rem

CSS 模块化

资料 https://github.com/css-modules/css-modules
css-loader支持 https://github.com/webpack-contrib/css-loader#modules

由于有vue-loader,所以CSS Modules可以完美地运用在vue文件上,当然还需要借助css-loader

需要用到css-loader,在里面配置

{
  test: /\.css$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        modules: {
          // 自定义类名生成规则,里面的[]里的值是变量,会被替换的
          localIdentName: '[path][name]---[local]---[hash:base64:10]'
        }
      } 
    }
  ]
}

这里可以看怎么配置自定义类名生成规则 https://github.com/webpack/loader-utils#interpolatename

比如我在css文件下填入

:local(.text) {
  color: pink;
}

现在打包后的css代码就是

.style---text---YuTc9Us6xQ {
  color: pink;
}

这是因为我上面配置了类名转化规则

localIdentName: '[path][name]---[local]---[hash:base64:10]'

设置路径别名

webpack.config.js里做如下配置

 resolve: {
      alias: {
        '@': path.join(__dirname, './src')
      }
    }

现在想引入src下的内容就可以直接import('@/......')这样引入了

定义全局变量

使用DefinePlugin这个插件,可以在打包编译时,把一些变量替换为我们自定义的数值,这个对于区分开发和生产很有帮助

const webpack = require('webpack')
//............
plugins: [
  new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
  })
]

如这里定义了PRODUCTION变量,但是需要注意的是,该变量不会在webpack.config.js里生效,就像process.env.NODE_ENV一样

https://webpack.docschina.org/plugins/define-plugin

除了使用插件,也可以使用命令行,定义我们的npm script为

 "scripts": {
    "build": "webpack --config webpack.prod.js --define PRODUCTION=true"
  }

这个--define会覆盖掉插件里的配置,我们可以跟据需求去改变npm script

处理vue

npm install vue-loader vue-template-compiler -D

webpack.config.js里配置loader,需要把style-loader替换为vue-style-loader

{
   test: /\.vue$/,
   loader: 'vue-loader',
   options: {
      loaders: {
      }
  	 // other vue-loader options go here
   }
},
{ 
  test: /\.css$/,
  use: [
     'vue-style-loader',  // 这里不是style-loader了
     'css-loader'
  ]
}

配置Vue插件,在webpack.config.js头部增加这个

const VueLoaderPlugin = require('vue-loader/lib/plugin');
//...
 plugins: [
    new VueLoaderPlugin(),
  ]
//...

但是这样生成的文件是没有css的,如果需要提取css,可以用上面说的MiniCssExtractPlugin,在vue-loader之前引入

  // ..................
 	{
        test: /\.css$/,
        use: [
          'vue-style-loader',
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
     }
    // ............

处理tailwindcss

npm install tailwindcss
npm install postcss-loader -D

之后配置webpack

//............
 	 {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: [
                require('tailwindcss'),
                require('autoprefixer')
              ]
            }
          }
        ]
      }
 //...........

之后创建tailwindcss.css

@tailwind base;

@tailwind components;

@tailwind utilities;

之后把tailwindcss.css全局引入到项目里,webpack就会把其打包

开发环境&生产环境

为了让webpack针对不同的环境,采取不同的打包方式,有几种方式来区分开发环境和生产环境

1,导出函数

原本我们的webpack.config.js文件是导出一个对象的,我们需要改变这个做法,改成导出一个返回原来配置对象的一个函数

let config = {
  entry: /*...........*/,
  output: //.............
  //....................
}
// 导出函数
module.exports = (env, argv) => {
  return config
}

介绍地址 https://webpack.docschina.org/configuration/configuration-types#exporting-a-function

可以看到该函数传入两个参数(env, argv) => {}

  • 第一个参数env是在CLI传入的环境选项,具体配置看https://webpack.docschina.org/api/cli/#%E7%8E%AF%E5%A2%83%E9%80%89%E9%A1%B9
  • 第二个参数argv可以i获取在CLI传入参数,如在CLI这样写webpack --mode=production,那么argv就可以获取到值,如argv.mode就可以获取到production

所以我们可以跟据这个来区分开发环境或者是生产环境,首先在package.json的npm script里配置

{
  "scripts": {
    "build": "webpack --mode=production --env.production",
    "build(dev)": "webpack --mode=development --env.production=false"
  }
}

webpack.config.js里这样写

module.exports = (env, argv) => {
  let config = {
    entry: /*...........*/,
    output: //.............
    //....................
  }
  if (argv.mode === 'development') {
    console.log('========== development ===========');
      console.log(env.production);
      console.log(process.env.NODE_ENV);
    console.log('========== development ===========');
    config.mode = 'development'
    config.devtool = 'inline-source-map'
    config.devServer = {
      contentBase: path.join(__dirname, './dist'),
      port: 8080
    }
    //...........
  }
  if (argv.mode === 'production') {
    console.log('========== production ===========');
      console.log(env.production);
      console.log(process.env.NODE_ENV);
    console.log('========== production ===========');
    config.mode = 'production';
    //...........
  }
  return config;
};

把config对象定义在函数里面,主要是为了让config里的配置可以用到env或者argv参数;
上面log的结果可以看到process.env.NODE_ENV并不会生效,这是因为这是在配置文件里,需要在src下的文件才可以按预期使用process.env.NODE_ENV
https://webpack.docschina.org/guides/production/#%E6%8C%87%E5%AE%9A-mode
如果想在webpack配置文件中访问当前环境变量,可以用env.production来代替,参考如下 https://github.com/webpack/webpack/issues/2537比如,在我们想在生产环境和开发环境使用不同的loader处理同种文件,如css文件,可以这样

 {
   test: /\.css$/,
   use: [
     env.production===true?MiniCssExtractPlugin.loader:'style-loader',
     'css-loader'
   ]
 }

2,分两个配置文件

https://webpack.docschina.org/guides/production/#cli-%E6%9B%BF%E4%BB%A3%E9%80%89%E9%A1%B9

把原来的webpack.config.js去掉,换成另外3个

  • webpack.common.js
  • webpack.dev.js
  • webpack.prod.js

webpack.common.js里配置了生产环境和开发环境都需要的共同配置,如入口文件,出口,插件,loader等等,而webpack.dev.jswebpack.prod.js都各种配置了各自环境的配置,但是,我们需要使用工具把webpack.common.js的内容加到另外两个文件中

npm install webpack-merge

webpack.common.js里照常和webpack.config.js一样,输出一个配置对象,另外两个如下:

  • webpack.dev.js
const path = require('path')
const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: path.join(__dirname, './dist'),
    port: 8080
  }
  //..........
})
  • webpack.prod.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  mode: 'production'
})

mode为production和development的区别是,打包出来的bundle有没有压缩

你可能感兴趣的:(前端)