webpack4构建前端项目

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Zckguiying/article/details/85646231

在使用webpack 4.x版本构建前端项目的时候,遇到了一些坑点,这里做一下记录,详细内容见注释。

1、项目目录:

2、基本配置内容

webpack.base.config.js

'use strict';
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//用于在构建前清除dist目录中的内容
const CleanWebpackPlugin = require('clean-webpack-plugin');

let baseWebpackConfig = {
  // 指定找入口文件所在文件夹
  context: path.resolve(__dirname, '../src/test'), // 这里是我做test的一个单独文件夹
  entry: './index.js',
  output: {
    // 打包出的文件名
    filename: '[name].bundle.[hash:8].js',
    // 打包出的文件输出路径
    path: path.resolve(__dirname, '../dist'),
    publicPath: "/" // 编译后模板文件地址
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/i,
        // use: ['babel-loader'],
        loader: 'babel-loader',
        exclude: /(node_modules|bower_components)/,
        options: {
          // This is a feature of `babel-loader` for webpack (not Babel itself).
          // It enables caching results in ./node_modules/.cache/babel-loader/
          // directory for faster rebuilds.
          cacheDirectory: true,
          plugins: ['react-hot-loader/babel'],
        }
      },
      {
        test: /\.(less|css)$/i,
        use:['css-hot-loader',MiniCssExtractPlugin.loader,"css-loader","less-loader",{
          loader: "postcss-loader",
          options: {
            ident: 'postcss',
            plugins: () => [
              require('autoprefixer')("last 100 versions")
            ]
          }
        }]
      },
      {
        test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000, // 大于就用文件形式,小于就压缩成base64
            name: 'img/[name].[hash:7].[ext]'
          }
        }]
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'media/[name].[hash:7].[ext]'
          }
        }]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'fonts/[name].[hash:7].[ext]'
          }
        }]
      }
    ]
  },
  plugins: [
    //用于在构建前清除dist目录中的内容
    new CleanWebpackPlugin(['dist'], {
      root: path.resolve(__dirname, '../'),       // 根目录
      verbose: true,                  // 开启在控制台输出信息
    }),
    // dist目录下生成html模板文件
    new HtmlWebpackPlugin({
      template: './index.html'
    }),
    // 样式代码分离
    // new ExtractTextWebpackPlugin('styles.css'), // (webpack4废弃)
    new MiniCssExtractPlugin({
      filename: "[name].css", // **注意**这里不能使用hash,否则无法实现热跟新,如果有hash需要,可以开发环境和生产环境分开配置成[name].[chunkhash:8].css
      chunkFilename: "[id].css" // 构建时生成的文件名
    })
  ],
  resolve: {
    // 设置自动解析的扩展
    extensions: ['.web.js', '.js', '.json', '.jsx', '.less', '.css'],
    // 设置路径别名
    alias: {
      '@': path.resolve(__dirname, '../src/')
    }
  }
};

module.exports = baseWebpackConfig;

3、本地开发环境dev服务器配置

webpack.dev.config.js

'use strict';
const PORT = 3000;
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.config');
const OpenBrowserWebpackPlugin = require('open-browser-webpack-plugin');

let webpackDevServerConfig = {
  mode: 'development',
  // 入口配置
  entry: [
    'babel-polyfill', // 原生支持
    'react-hot-loader/patch', // 局部更新
    './index.js'
  ],
  devtool: 'cheap-module-source-map',
  plugins: [
    // 美化 console 输出
    new webpack.NamedModulesPlugin(),
    // 开启全局的模块热替换(HMR)
    new webpack.HotModuleReplacementPlugin(),
    // 编译完成在再浏览器打开项目
    new OpenBrowserWebpackPlugin({url: `http://0.0.0.0:${PORT}`}), // {url: `http://localhost:${PORT}`}
    // 编译时定义全局变量,用于判断执行环境 | 配合cross_env插件使用,它是运行跨平台设置和使用环境变量的脚本
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      }
    })
  ],
  devServer: {
    // hot: true,
    hotOnly: true, // 只热替换,不自动刷新
    port: PORT,
    inline: true, // 实时刷新
    publicPath: baseWebpackConfig.output.publicPath,
    host: '0.0.0.0',
    // 是否关闭用于DNS重绑定的HTTP请求的host检查,它通常用于搭配 --host 0.0.0.0 使用,
    // 因为你想要其它设备访问你本地的服务,但访问时是直接通过 IP 地址访问而不是 HOST 访问,所以需要关闭 HOST 检查。
    disableHostCheck: true,
    // 把项目根目录下的src目录设置成DevServer服务器的文件根目录
    contentBase: path.resolve(__dirname, 'src'),
    // 可以保证类似http://localhost:8080/aa的请求返回跟http://localhost:8080/一样的页面,
    // 这样才能用同一个js根据路径的不同去往不同的路由
    historyApiFallback: true
  },
  // dev环境打包的单个js文件可能过大,通过该方式取消警告
  performance: {
    hints: process.env.NODE_ENV === 'development' ? false : 'warning'
  }
};
module.exports = merge(baseWebpackConfig, webpackDevServerConfig)

4、生产打包配置

webpack.build.config.js

'use strict';
const merge = require('webpack-merge');
const webpack = require('webpack');
const baseWebpackConfig = require('./webpack.base.config.js');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

let webpackBuildConfig = {
  mode: 'production',
  // 入口配置
  entry: [
    'babel-polyfill', // 浏览器原生支持
    'react-hot-loader/patch', // 局部更新
    './index.js'
  ],
  plugins: [
    new UglifyJSPlugin({
      sourceMap: true
   }),
    // 编译时定义全局变量,用于判断执行环境
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      }
    })
  ]
};

module.exports = merge(baseWebpackConfig, webpackBuildConfig);

5、package.json对scripts属性配置

核心代码:

"test": "echo \"Error: no test specified\" && exit 1",
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.config.js",
"build": "cross-env NODE_ENV=production webpack -p --config build/webpack.build.config.js"

package.json

6、test目录下的一些测试文件

<1>、 index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>test-html</title>
</head>
<body>
  <div id="test"></div>

</body>
</html>

<2>、index.js

import React from 'react'
import ReactDom from 'react-dom'
import { AppContainer } from 'react-hot-loader';
import './style.less'
import bigImg from './imgs/big-test.png'
import smallImg from './imgs/small-test.png'

let html = <div className='wrapper'>
  <h1 className='test'>hello webpack!</h1>
  <span>16.4kb---></span><img src={bigImg} />
  <span>6.09kb---></span><img src={smallImg} />
</div>

ReactDom.render(
  <AppContainer>
    {html}
  </AppContainer>,
  document.getElementById('test')
)

// HMR 接口
if (module.hot) {
  // 实现热更新
  module.hot.accept()
}

<3>、style.less

.wrapper{
  display: flex;
  flex-direction: column;
  align-items: center;
  .test{
    border-radius: 5px;
    flex: 1;
    color: black
  }
}

7、.babelrc的配置

{
  "presets": [
    [
      "es2015",
      {
        "modules": false
      }
    ],
    "react",
    "stage-0"
  ],
  "plugins": [
    "react-hot-loader/babel",
    "transform-runtime"
  ]
}

猜你喜欢

转载自blog.csdn.net/Zckguiying/article/details/85646231