webpack配置文件

  • RemService.js
/**
 * 将hotcss改成一个es6模块
 */
class RemHot {
  constructor() {
    this.lib = {};
  }

  init() {
    const { lib } = this;
    const win = window;
    const doc = win.document;
    const docEl = doc.documentElement;
    let metaEl = doc.querySelector('meta[name="viewport"]')
    const flexibleEl = doc.querySelector('meta[name="flexible"]');
    let dpr = 0;
    let scale = 0;
    let tid;
    const flexible = lib.flexible || (lib.flexible = {});

    if (metaEl) {
      console.warn('将根据已有的meta标签来设置缩放比例');
      const match = metaEl.getAttribute('content').match(/initial-scale=([\d.]+)/);
      if (match) {
        scale = parseFloat(match[1]);
        dpr = parseInt(1 / scale, 10);
      }
    } else if (flexibleEl) {
      const content = flexibleEl.getAttribute('content');
      if (content) {
        const initialDpr = content.match(/initial-dpr=([\d.]+)/);
        const maximumDpr = content.match(/maximum-dpr=([\d.]+)/);
        if (initialDpr) {
          dpr = parseFloat(initialDpr[1]);
          scale = parseFloat((1 / dpr).toFixed(2));
        }
        if (maximumDpr) {
          dpr = parseFloat(maximumDpr[1]);
          scale = parseFloat((1 / dpr).toFixed(2));
        }
      }
    }

    const isIPhone = win.navigator.appVersion.match(/iphone/gi);
    if (!dpr && !scale) {
      const { devicePixelRatio } = win;
      if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
          dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
          dpr = 2;
        } else {
          dpr = 1;
        }
      } else {
        // 其他设备下,仍旧使用1倍的方案
        dpr = 1;
      }
      scale = 1 / dpr;
    }

    docEl.setAttribute('data-dpr', dpr);
    if (!metaEl) {
      metaEl = doc.createElement('meta');
      metaEl.setAttribute('name', 'viewport');
      metaEl.setAttribute(
        'content',
        `initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no`,
      );
      if (docEl.firstElementChild) {
        docEl.firstElementChild.appendChild(metaEl);
      } else {
        const wrap = doc.createElement('div');
        wrap.appendChild(metaEl);
        doc.write(wrap.innerHTML);
      }
    }

    function refreshRem() {
      let { width } = docEl.getBoundingClientRect();
      if (width / dpr > 540) {
        width = 540 * dpr;
      }
      const rem = width / 10;
      docEl.style.fontSize = `${rem}px`;
      doc.body.classList.add(isIPhone ? 'ios' : 'android');
      if (win.navigator.appVersion.match(/android/gi)) {
        // 好医生老版本app存在部分机型webview字体大小随系统字体大小放大 以下代码禁止页面字体大小跟随系统字体放大
        const realfz =
          // eslint-disable-next-line no-bitwise
          ~~(
            +window
              .getComputedStyle(document.getElementsByTagName('html')[0])
              .fontSize.replace('px', '') * 10000
          ) / 10000;
        if (rem !== realfz) {
          document.getElementsByTagName('html')[0].style.fontSize = `font-size: ${
            rem * (rem / realfz)
          }px`;
        }
      }
      flexible.rem = rem;
      win.rem = rem;
    }

    win.addEventListener(
      'resize',
      () => {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
      },
      false,
    );
    win.addEventListener(
      'pageshow',
      e => {
        if (e.persisted) {
          clearTimeout(tid);
          tid = setTimeout(refreshRem, 300);
        }
      },
      false,
    );

    if (doc.readyState === 'complete') {
      doc.body.style.fontSize = `${12 * dpr}px`;
    } else {
      doc.addEventListener(
        'DOMContentLoaded',
        () => {
          doc.body.style.fontSize = `${12 * dpr}px`;
        },
        false,
      );
    }

    refreshRem();

    flexible.dpr = dpr;
    win.dpr = dpr;
    flexible.refreshRem = refreshRem;
    flexible.rem2px = d => {
      let val = parseFloat(d) * this.lib.flexible.rem;
      if (typeof d === 'string' && d.match(/rem$/)) {
        val += 'px';
      }
      return val;
    };
    flexible.px2rem = d => {
      let val = parseFloat(d) / this.rem;
      if (typeof d === 'string' && d.match(/px$/)) {
        val += 'rem';
      }
      return val;
    };
  }
}
const remHot = new RemHot();
window['remHot'] = remHot;
export default remHot;

  • PolyfillService.ts
import "core-js/es/promise";
import "core-js/es/array/includes";
import "core-js/es/array/find";
import "core-js/es/array/find-index";
import "core-js/es/array/fill";
import "core-js/es/array/from";
  • .prettierrc
{
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "proseWrap": "never",
  "arrowParens": "always",
  "overrides": [
    {
      "files": ".prettierrc",
      "options": {
        "parser": "json"
      }
    }
  ]
}

  • .babelrc
{
    "presets": [
        ["@babel/preset-env", {
            "modules": "commonjs"
        }],
        "@babel/react"
    ],
    "plugins": [
        "syntax-dynamic-import",
        "@babel/proposal-class-properties"
    ]
}
  • 脚本package.json
    "start": "webpack-dev-server --config webpack.dev.ts",
    "build": "npm rebuild node-sass && NODE_ENV=production webpack --config webpack.prod.ts --profile --bail",
    "prod": "npm run build && cd dist && static -p 9699",
  • tsconfig.json
{
    "compilerOptions": {
        // 源码根目录
        "baseUrl": "./src/",
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": false,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react",
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "allowJs": true,
        "lib": ["es2015", "dom", "es2016"],
        "importHelpers": true,
        "experimentalDecorators": true,
        "downlevelIteration": true
    },
    "include": ["./src/**/*"],
    "exclude": ["node_modules", "src/**/*.spec.*"]
}
  • webpack.common.ts
import path from 'path';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import Settings from './src/config';

const srcPath = './src';
const packageInfo = require('./package.json');

const isProduction = process.env.NODE_ENV === 'production';

/**
 * 基本配置信息
 */
const configBase: webpack.Configuration = {
  context: __dirname,
  target: 'web',
  entry: {
    react: ['react', 'react-dom'],
    vendor: ['react-cookie', 'axios', 'tslib', 'qs', 'zscroller', 'react-portal', 'path-to-regexp', 'moment'],
    // lib: ['chart.js'],
    app: ['./src/utils/PolyfillService.ts', './src/index.tsx'],
  },
  optimization: {
    namedChunks: true,
    splitChunks: {
      chunks: 'all',
      // minSize: 300000,
      cacheGroups: {
        // vendor chunk
        react: {
          chunks: 'all',
          name: 'react',
          test: 'react',
          enforce: true,
          priority: 10,
        },
        lib: {
          chunks: 'all',
          name: 'lib',
          test: 'lib',
          enforce: true,
          priority: 10,
        },
        vendor: {
          chunks: 'all',
          name: 'vendor',
          test: 'vendor',
          enforce: true,
          priority: 0,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
    // runtimeChunk: {
    //     name: "manifest",
    // }
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'string-replace-loader',
            options: {
              search:
                'Promise\\.resolve\\(\\)\\.then\\(function \\(\\) \\{[^r]+return [^(]+\\(require\\(([^)]+)\\)\\);[^)]+\\)',
              // replace: 'import(/* webpackChunkName: $1 */$1)',
              replace: (match, p1) => {
                return `import(/* webpackChunkName: "${p1
                  .split('/')
                  .pop()
                  .toLocaleLowerCase()
                  .replace(/'/g, '')}" */${p1})`;
              },
              flags: 'g',
            },
          },
          'ts-loader',
        ],
        exclude: /node_modules/,
      },
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.(sa|sc)ss$/,
        use: [
          isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              // eslint-disable-next-line global-require
              plugins: [require('autoprefixer')],
            },
          },
          {
            loader: 'px2rem-loader',
            options: {
              baseDpr: 2,
              remUnit: 75,
              remPrecision: 8,
            },
          },
          {
            loader: 'sass-loader',
            options: {
              sassOptions: {
                outputStyle: 'expanded',
              },
            },
          },
          {
            loader: 'sass-resources-loader',
            options: {
              resources: [`${srcPath}/styles/_ui_variables.scss`, `${srcPath}/styles/_mixins.scss`],
            },
          },
        ],
      },
      {
        test: /\.css$/,
        use: [
          isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
          {
            loader: 'px2rem-loader',
            options: {
              baseDpr: 1,
              remUnit: 37.5,
              remPrecision: 8,
            },
          },
        ],
      },
      {
        test: /\.(png|jpg|gif)\??.*$/,
        loader: 'url-loader',
        options: {
          limit: '1024',
          publicPath: (url) => {
            return `/${packageInfo.name}/${url}`;
          },
          name: 'images/[name].[hash:16].[ext]',
          esModule: false,
        },
      },
      {
        test: /\.(woff|woff2|eot|ttf|svg)\??.*$/,
        loader: 'url-loader',
        query: {
          limit: '8192',
          publicPath: '../',
          name: './fonts/[name].[hash:16].[ext]',
          useRelativePath: false,
        },
      },
    ],
  },
  resolve: {
    // 设置根目录
    modules: [path.join(__dirname, './src'), 'node_modules'],
    extensions: ['.tsx', '.ts', '.js', '.jsx'],
  },
  output: {
    path: path.join(__dirname, './dist'),
    publicPath: '',
    chunkFilename: isProduction
      ? 'scripts/modules/[id].[contenthash].js'
      : 'scripts/modules/[id].[hash].js',
    filename: isProduction ? 'scripts/[name].[contenthash:8].js' : 'scripts/[name].[hash:8].js',
  },
  plugins: [
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
    new HtmlWebpackPlugin({
      template: './src/index.ejs',
      minify: {
        minifyJS: true,
        collapseWhitespace: true,
        removeComments: true,
        removeScriptTypeAttributes: true,
      },
      title: Settings.TRADE_MARK_TITLE,
      shortCutIcon: Settings.TRADE_MARK_ICON,
      spmHost: Settings.SPM_HOST, // 是否注入spm打点js
      projectName: packageInfo.name, // 项目名
      spmProjectName: packageInfo.name, // SPM打点项目名
    }),
  ],
};
export default configBase;

  • webpack.dev.ts
import path from 'path';
import merge from 'webpack-merge';
import BundleAnalyzer from 'webpack-bundle-analyzer';
import configBase from './webpack.common';
 
const webpack = require('webpack')
// 本地开发端口号
const devPort = 9865;
/**
 * 开发环境配置项
 */
const webpackDevConfig = merge(configBase, {
  mode: 'development',
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: devPort,
    historyApiFallback: true,
    disableHostCheck: true,
    hot: true,
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
});

// 添加bundle分析
webpackDevConfig.plugins.push(new BundleAnalyzer.BundleAnalyzerPlugin({ analyzerPort: 8891 }));
export default webpackDevConfig;
  • webpack.prod.ts
import TerserPlugin from 'terser-webpack-plugin';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import merge from 'webpack-merge';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import configBase from './webpack.common';
// import BundleAnalyzer from "webpack-bundle-analyzer";

/**
 * 线上打包环境配置项
 */
const webpackProdConfig = merge(configBase, {
  optimization: {
    minimizer: [
      // new UglifyJsPlugin({
      //     cache: true,
      //     parallel: true,
      //     sourceMap: false
      // }),
      new TerserPlugin(),
      new OptimizeCSSAssetsPlugin({}),
    ],
  },
  performance: {
    hints: 'warning',
    maxAssetSize: 200000,
    maxEntrypointSize: 400000,
  },
  mode: 'production',
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: 'styles/[name].[contenthash:8].css',
      chunkFilename: 'styles/[id].[contenthash:8].css',
    })],
});
// 清空dist目录
webpackProdConfig.plugins.unshift(
  new CleanWebpackPlugin({ cleanAfterEveryBuildPatterns: ['dist'] }),
);
webpackProdConfig.plugins.unshift(
  new CopyWebpackPlugin({
    patterns: [{ from: './src/favicon.ico' }],
  }),
);
// webpackProdConfig.plugins.push(new BundleAnalyzer.BundleAnalyzerPlugin({ analyzerPort: 8899 }));
export default webpackProdConfig;

### 关于 Webpack 配置文件的信息 #### Webpack 配置概述 Webpack 的配置是通过一个名为 `webpack.config.js` 的文件来完成的,此文件定义了入口、输出、加载器以及插件等内容[^2]。 #### 基本配置实例 对于一个简单的项目结构而言: ```plaintext my-project/ ├── src/ │ └── components/ │ └── App.js └── webpack.config.js ``` 对应的最基础版本的 `webpack.config.js` 文件可以这样编写[^3]: ```javascript const path = require('path'); module.exports = { entry: './src/components/App.js', // 入口起点 output: { // 输出选项 filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { // 模块规则 (例如处理不同类型的模块) rules: [ { test: /\.js$/, // 使用正则表达式匹配 js 文件 exclude: /node_modules/, // 排除 node_modules 中的内容 use: { loader: 'babel-loader' // 使用 Babel 编译 JavaScript } } ] }, plugins: [], // 插件用于执行构建过程中的特定任务 }; ``` 上述代码片段展示了如何设置基本的 Webpack 构建流程,包括指定输入文件的位置 (`entry`) 和编译后的资源应该放置在哪里 (`output`)。同时也指定了当遇到 `.js` 结尾的文件时应该如何处理——这里选择了使用 `babel-loader` 来转换现代 JavaScript 特性以便兼容旧版浏览器。 #### 安装必要的依赖包 为了使上面的例子正常工作,在命令行工具中运行以下指令以安装所需的开发环境依赖项: ```bash npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env ``` 这会将 Webpack 及其 CLI 工具作为项目的开发阶段依赖加入到 package.json 文件里,并且还会安装 Babel 相关组件用来支持 ES6+ 新特性转码操作[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值