美文网首页
webpack 4.x 入门

webpack 4.x 入门

作者: 麦子_Peng | 来源:发表于2018-08-31 09:44 被阅读0次

    webpack都更新到4.17.x了,官网的文档有一部分还停留在4.x以下,因此写下这篇文章,以便后续遇到坑的时候再次抓耳挠腮。

    项目地址: webpack4-skeleton

    目录结构

    ├── dist                      打包输出目录
    ├── node_modules              npm安装的依赖包目录
    ├── public                    静态资源目录
    │   ├── static                第三方静态文件目录
    │   │   └── images            静态图片目录
    │   ├── favicon.ico           网页图标
    │   └── index.html            入口html
    ├── src                       开发源代码目录
    │   ├── assets                静态文件目录
    │   │   ├── css               样式文件目录
    │   │   ├── fonts             字体目录
    │   │   ├── img               静态图片目录
    │   │   └── js                公共函数目录
    │   ├── components            可以复用的模块目录
    │   ├── pages                 页面存放目录
    │   └── index.js              入口js
    ├── webpack-config            webpack配置目录
    │   ├── common.js             配置文件入口
    │   ├── dev.js                开发环境配置
    │   └── prod.js               生产环境配置
    ├── .eslintignore             ESlint忽略文件配置信息
    ├── .eslintrc.js              ESlint配置信息
    ├── babel.config.js           babel配置信息
    └── package.json              项目配置信息
    

    初始化项目

    npm init

    按照提示配置项目的基础信息后,即可在项目文件夹下到生成了package.json文件。

    用ESlint检查语法规范

    首先安装必要的package

    npm i -D eslint eslint-config-airbnb-base babel-eslint eslint-loader eslint-plugin-html eslint-plugin-import

    由于airbnb的规范过于严格,创建.eslintrc.js,创建自定义配置文件。

    module.exports = {
      extends: "airbnb-base", // 继承airbnb的语法检测规则
      root: true,
      env: {
        node: true,
        browser: true,        // 检测环境基于浏览器,避免在调用window对象的时候报错
      },
      rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
        'strict': 0,
        'no-param-reassign': ["error", {
          "props": false,               // 允许给函数的参数重新赋值
        }],
        'max-len': ["error", {
          "code": 240,                  // 允许单行代码最长为240个字符
        }],
        'no-plusplus': ["error", {
          "allowForLoopAfterthoughts": true, // 允许在for循环中用 i++写法
        }],
        'no-new': 'off',                     // 允许new Object()
        'class-methods-use-this': 'off',     // 允许class中的function内不使用this
        'import/no-unresolved': 0,           // 避免webpack指定alias,后eslint报错
      },
      plugins: [
        'html'
      ],
      parser: 'babel-eslint'
    };
    

    接下来创建.eslintignore,忽略开发时源代码之外的文件。

    /node_modules/
    /webpack-config/
    /dist/
    /public/
    /static/
    /*.js
    

    安装webpack、babel和必要的webpack loader及webpack plugin

    npm i -D webpack webpack-cli webpack-dev-server "@babel/core" "@babel/plugin-syntax-dynamic-import" "@babel/plugin-transform-async-to-generator" "@babel/plugin-transform-regenerator" "@babel/plugin-transform-runtime" "@babel/preset-env" "@babel/runtime" babel-loader css-loader file-loader html-loader@next html-webpack-plugin@next less less-loader regenerator-runtime style-loader url-loader

    html-webpack-plugin@next 安装最新的alpha版本是为了解决以下bug:

    Fail to inject code-splitting script files when webpack 4 optimization.splitChunks.name: false

    html-loader@next 安装最新的alpha版本是因为webpack 4.x已经禁用了html-loader的htmlLoader选项,安装alpha版可以Disable HTML Assets。

    配置webpack的开发环境

    首先安装必要的package

    npm i -D copy-webpack-plugin friendly-errors-webpack-plugin webpack-merge

    • copy-webpack-plugin 用来拷贝静态资源
    • friendly-errors-webpack-plugin 能够更好在终端看到webapck运行的警告和错误
    • webpack-merge 用来合并多个webpack的配置文件

    然后创建配置文件common.jsdev.jsprod.jscommon.js存放开发环境和生产环境公用的配置:

    const { resolve } = require('path');
    const webpack = require('webpack');
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
    const merge = require('webpack-merge');
    
    const prodConfig = require('./prod.js');
    const devConfig  = require('./dev.js');
    
    const commonConfig = {
      output: {
        filename: 'js/[name].js',
        chunkFilename: 'js/[name].[chunkhash].js',
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [{
              loader: 'babel-loader',
            }, {
              loader: 'eslint-loader',
            }],
          }, {
            test: /\.html$/,
            use: [{
              loader: 'html-loader',
              options: {
                url: false,
              }
            }],
          }, {
            test: /\.(png|jpg|jpeg|gif|bmp)(\?.+)?$/,
            include: [resolve(__dirname, '../src/assets')],
            exclude: [resolve(__dirname, '../public/static')],
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 20480,
                  name: '[name].[ext]',
                  outputPath: 'img',
                },
              },
            ],
          }, {
            test: /\.(eot|ttf|woff|woff2|svg)(\?.+)?$/,
            use: [
              {
                loader: 'file-loader',
                options: {
                  name: '[name].[ext]',
                  outputPath: 'fonts',
                },
              },
            ],
          },
        ],
      },
      plugins: [
        new CopyWebpackPlugin([{
          from: resolve(__dirname, '../public/static'),
          to: resolve(__dirname, '../dist/static'),
        }]),
        new webpack.HashedModuleIdsPlugin(),
        new webpack.NamedModulesPlugin(),
        new FriendlyErrorsWebpackPlugin(),
      ],
      resolve: {
        extensions: ['.js', '.css', '.less'],
        alias: {
          '@': resolve(__dirname, '../src'),
          'assets': resolve(__dirname, '../src/assets'),
        },
      },
    };
    
    module.exports = function(env, argv) {
      const config = argv.mode === 'production' ? prodConfig : devConfig;
      return merge(commonConfig, config);
    };
    

    接下来配置开发环境dev.js:

    const { resolve } = require('path');
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      mode: 'development',
      devtool: 'cheap-module-eval-source-map',
      output: {
        path: resolve(__dirname, '../dist'),
        publicPath: '',
      },
      module: {
        rules: [
          {
            test: /\.(le|c)ss$/,
            use: ['style-loader', 'css-loader', 'less-loader'],
          }
        ],
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: 'public/index.html',
          favicon: 'public/favicon.ico',
          filename: 'index.html',
        }),
        new webpack.HotModuleReplacementPlugin(),
      ],
      performance: {
        hints: false,
      },
      stats: 'errors-only',
      devServer: {
        contentBase: '../dist',
        hot: true,
        host: 'localhost',
        port: 8050,
        stats: 'errors-only',
        overlay: true,
      }
    };
    

    修改package.json,添加script脚本:

    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --open --progress --config webpack-config/common.js",
        "build": "webpack --mode production --progress --config webpack-config/common.js"
      },
    }
    

    执行npm run dev就会看到浏览器自动加载页面,如果现在修改和保存任意源文件,web 服务器就会自动重新加载编译后的代码,这意味着开发环境就配置完成了。

    写几个页面跑起来

    开始撸页面代码,具体可以查看项目代码webpack4-skeleton,略过......

    配置webpack的生产环境

    首先安装必要的package

    npm i -D mini-css-extract-plugin uglifyjs-webpack-plugin optimize-css-assets-webpack-plugin clean-webpack-plugin

    • mini-css-extract-plugin 从 bundle 中提取css到单独的文件
    • optimize-css-assets-webpack-plugin 优化css打包
    • uglifyjs-webpack-plugin 控制项目中 UglifyJS
    • clean-webpack-plugin 清除上次打包的文件

    编辑prod.js

    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    
    module.exports = {
      mode: 'production',
      devtool: 'none',
      output: {
        path: resolve(__dirname, '../dist/static'),
        publicPath: './static/', // 使用相对路径而不是绝对路径可以避免在hybird App框架中因为找不到路径报错
      },
      module: {
        rules: [
          {
            test: /\.(le|c)ss$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  publicPath: '../',
                },
              },
              'css-loader',
              'less-loader',
            ],
          }
        ],
      },
      plugins: [
        new CleanWebpackPlugin(['dist/*'], {
          root: resolve(__dirname, '../'), // 指定root可以避免由于清理目录超出根目录而跳过清理
        }),
        new HtmlWebpackPlugin({
          template: 'public/index.html',
          favicon: 'public/favicon.ico',
          filename: '../index.html',
        }),
        new MiniCssExtractPlugin({
          filename: "css/[name].css",
          chunkFilename: "css/[name].[chunkhash].css",
        }),
      ],
      optimization: {
        runtimeChunk: true,
        splitChunks: {
          chunks: 'all',
          name: true,
        },
        minimizer: [
          new UglifyJsPlugin({
            cache: true,
            parallel: true,
            sourceMap: false, // set to true if you want JS source maps
          }),
          new OptimizeCSSAssetsPlugin({})
        ],
      },
      performance: {
        hints: 'warning',
        assetFilter: function(assetFilename) {
          return assetFilename.endsWith('.js') ||  assetFilename.endsWith('.css');
        },
      },
      stats: 'errors-only',
    };
    

    执行npm run build,打包生产环境的代码。

    相关文章

      网友评论

          本文标题:webpack 4.x 入门

          本文链接:https://www.haomeiwen.com/subject/gizjwftx.html