Webpack4 +babel7 多入口配置详细教程

最近需要新开一个项目,用于公众号的基础服务搭建,可能对接多个平台。
项目各页面基本无关联,需要多个 HTML 文件,多个入口 JS,看了一下网上没有类似的比较全面的 Webpack 配置教程,所以写一篇较为详细的配置过程,自己去写一个 Demo。
项目 Demo 在这里,release@4/babel7 分支下 => 多入口 Webpack 配置

环境(MAC)

node 10.13.0
npm 6.4.1
webpack 4+
babel 7

项目 Init

首先需要全局安装 node、npm、webpack、webpack-cli 不细说
本文安装使用 cnpm,可以自行 Google 设置

然后初始化项目,按照自己的需求填写配置。

$ npm init

我这里初始化后 package.json 中有很多包,感觉没有什么用处都删除掉了,如下图。
在这里插入图片描述

修改后的 package.json 如下

{
  "name": "module_web",
  "version": "1.0.0",
  "description": "A web project",
  "author": "WenJW <***@163.com>",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "test": "webpack",
    "build": "node build/build.js"
  },
  "dependencies": {
  },
  "devDependencies": {
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/lwpersonal/module_Vue2.git"
  },
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/lwpersonal/module_Vue2/issues"
  },
  "homepage": "https://github.com/lwpersonal/module_Vue2#readme"
}

下面先创建一些会用到的项目配置文件和目录
某些文件不会详细说明,可以自行查阅相关资料,一些重要的文件后面会详细介绍

root
+-- build // 项目打包配置目录
+-- config // 项目配置文件
+-- dist // 打包后的文件输出目录
+-- src // 前端代码
+-- service // 后端代码
+-- .babelrc // babel 配置文件
+-- .eslintignore // 忽略 eslint 检测
+-- .eslintrc.js // eslint 配置
+-- .gitignore // 忽略 git 检测
+-- .npmrc // npm 配置
+-- .nvmrc // node 版本 控制
+-- package.json
+-- ...

然后项目目录下安装 webpack、webpack-cli

$ cnpm i -D webpack webpack-cli
// 这里简单说一下安装命令的简写和规范
// i => install
// -D => --save-dev
// -S => --save
// -S 会安装到 dependencies 属性下
// -D 安装到 devDependencies 属性下
// 规范是,-S 安装项目中会用到的代码,例如 vue、react、lodash 等
// -D 安装构建代码,不会在项目代码中使用,例如 webpack、css-loader 等

我们可以先简单测试一下 webpack 的命令
在 src 中创建一个 index.js 的入口文件
这里说明一下,webpack4 的默认入口文件,为项目 src 目录下的 index.js,如果没有此文件,会报错;默认输出为 dist/main.js

// /src/index.js
const a = 4

然后执行命令

$ webpack --mode production

在这里插入图片描述
在 dist 目录下可以看到输出的 main.js 文件,里面是构建后的代码,项目的基本结构就是这样了。

下面就进行详细的配置了,我们可以想一下项目中会打包什么文件?

  • html
  • es6
  • css预编译,scss、less
  • 图片字体资源
  • ……

我们一步步完善 webpack 的配置去处理这些模块

build

build 目录的拆分与 vue-cli 一致

// build
build.js // 生产环境打包入口
check-versions.js // npm 包版本检测
utils.js // 公共模块
vue-loader.conf.js
webpack.base.conf.js // development、production 环境公共配置
webpack.dev.conf.js // dev 配置
webpack.prod.conf.js // prod 配置

下面我们先配置 dev 的打包环境
创建多个入口文件
在这里插入图片描述
目标是输出结果互相不耦合,且 html 可以正确引入对应的的 js 文件

首先在 webpack.dev.conf.js 中简单的进行配置

'use strict'

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')

const resolve = (dir) => {
  return path.join(__dirname, '..', dir)
}

const webpackConfig = {
  mode: 'development', // webpack4 需要指定编译环境
  context: path.resolve(__dirname, '../'), // 下面的配置会以这里为解析入口点
  entry: {
    app1: './src/pages/app1/index.js', // 前面的属性 app1、app2 是下面的 [name],chunks
    app2: './src/pages/app2/index.js'
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name]/[name].bundle.js',
    publicPath: '/' // 此选项指定在浏览器中引用时输出目录的公共URL
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      }
    ]
  },
  plugins: [
    // 多个文件需要多次实例化
    new HtmlWebpackPlugin({
      filename: './app1/index.html', // 输出目录
      template: './src/pages/app1/index.html', // 模版文件
      inject: true, // 引入 js 的位置,body 底部
      chunks: ['app1'] // 只引入 app1 的 js 代码,这里必须是一个数组,单个的字符串会全部引入
    }),
    new HtmlWebpackPlugin({
      filename: './app2/index.html',
      template: './src/pages/app2/index.html',
      inject: true,
      chunks: ['app2']
    }),
  ],
  node: {
    setImmediate: false,
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

module.exports = webpackConfig

这里使用 babel7 去编译 ES6 的代码,需要配置 .babelrc 文件
首先安装对应的插件

$ cnpm i -D html-webpack-plugin
$ cnpm i -D babel-loader
$ cnpm i -D @babel/runtime
$ cnpm i -D @babel/preset-env
$ cnpm i -D @babel/plugin-transform-runtime
$ cnpm i -D @babel/core

然后配置

// .babelrc

// targets, useBuiltIns 等选项用于编译出兼容目标环境的代码
// 其中 useBuiltIns 如果设为 "usage"
// Babel 会根据实际代码中使用的 ES6/ES7 代码,以及与你指定的 targets,按需引入对应的 polyfill
// 而无需在代码中直接引入 import '@babel/polyfill',避免输出的包过大,同时又可以放心使用各种新语法特性。
{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      },
      "useBuiltIns": "usage"
    }]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

我们改造一下我们的示例文件,在 js 中写一些 ES6 的代码
在这里插入图片描述
然后编译运行一下

// 加 --config 可以查看详细的报错信息,便于排查错误
$ webpack --config build/webpack.dev.conf.js

在这里插入图片描述
可以看到成功编译的信息
我们在 dist 目录下开一个服务器去测试

$ cd dist/
$ http-server -p10099 -o
// 这里安利一个很好用的插件,http-server,可以很方便的开一个测试服务器

执行命令后会自动打开浏览器,localhost:10099,我这里由于修改了 host 所以会不同
在这里插入图片描述

点击对应的路由可以访问对应的页面,这里我们进入到 app2,可以看到代码已经正确编译为 ES5
在这里插入图片描述

不同的 html 文件也正确的引入了对应 chunks 的 js
在这里插入图片描述

在这里插入图片描述

这里构建的基本流程已经完成了,当然现在的代码比较混乱,后面会陆续对代码进行抽离,完善项目的构建流程。

上面的配置遇到的较为麻烦的错误是这个,找了很多资料都没有解决。我这里是由于配置项的数据类型错误导致的问题。
在这里插入图片描述
后面用 --config 重新跑了一下就定位到问题了。所以遇到错误还是多看日志去慢慢排查。
在这里插入图片描述

完善构建流程

我们把 dev 构建中的通用配置抽离,然后写入 webpack.base.conf.js 文件中
仔细分析可以发现,一些配置例如:entry、output、module等大部分是可以通用的
plugins 插件这一块大部分都需要分别去配置
还有一些公共的函数和项目端口配置等,都是可以抽离的

下面的大部分都是由 vue-cli 改造来的
具体体现在 build 和 config 目录下,例如 config 下的 dev.env.js、prod.env.js 等都是没有改变的,具体可以去我的 Demo 中查看代码,下面只会提到改动和新增的部分

首先我们把 config 配置抽离,创建不同环境下的 config 文件

// config/config.dev.js

"use strict"
module.exports = {
  "port": 10011,
  "server": {
    "port": 10012
  },
  cdn: '',
  "timeOut": 10000,
  “api”: {
  	...
  }
}

// config.prod.js 文件类似,根据情况设置线上的 api 和 cdn 等

第一次启动项目时,复制一份 dev 的配置到 config/config.js,后续在配置中引入 config.js
这里需要注意,因为 config.js 文件,线上和本地是区分的,所以需要在 .gitignore 文件中去掉 git 检测

$ cp ./config/config.dev.js ./config/config.js

由于是多个入口,且后续可能会继续添加,我们写一个入口文件的配置,方便后面去维护

./config/app_list.js

'use strict'
// pages 目录下
module.exports = {
  app1: {
    html: 'app1/index.html',
    js: 'app1/index.js'
  },
  app2: {
    html: 'app2/index.html',
    js: 'app2/index.js'
  }
}

项目根目录下添加了一个 postcss.config.js,否则新版的 webpack 会报错

/postcss.config.js

module.exports = {
  plugins: {
    'autoprefixer': {
      browsers: 'last 5 version'
    }
  }
}

将一些打包配置抽离到 config/index.js
可以根据需求自行更改

// config/index.js
'use strict'
const path = require('path')
const config = require('./config')

module.exports = {
  base: {
    pathPrefix: './src/pages/' // 打包入口目录
  },
  dev: {
    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},

    // Various Dev Server settings
    host: 'localhost', // can be overwritten by process.env.HOST
    port: config.port, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

    // Use Eslint Loader?
    // If true, your code will be linted during bundling and
    // linting errors and warnings will be shown in the console.
    useEslint: true,
    // If true, eslint errors and warnings will also be shown in the error overlay
    // in the browser.
    showEslintErrorsInOverlay: false,

    /**
     * Source Maps
     */

    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',

    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,

    cssSourceMap: true
  },

  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

改动 utils.js 文件,加入我们自己的配置

// build/utils.js

'use strict'
const path = require('path')
const config = require('../config')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const packageConfig = require('../package.json')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const appList = require('../config/app_list')

exports.assetsPath = function (_path) {
  const assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory

  return path.posix.join(assetsSubDirectory, _path)
}

exports.cssLoaders = function (options) {
  options = options || {}

  const cssLoader = {
    loader: 'css-loader',
    options: {
      sourceMap: options.sourceMap
    }
  }

  const postcssLoader = {
    loader: 'postcss-loader',
    options: {
      sourceMap: options.sourceMap
    }
  }

  // generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return [MiniCssExtractPlugin.loader].concat(loaders)
    } else {
      return ['style-loader'].concat(loaders)
    }
  }

  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}

exports.styleLoaders = function (options) {
  const output = []
  const loaders = exports.cssLoaders(options)

  for (const extension in loaders) {
    const loader = loaders[extension]
    output.push({
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }

  return output
}

// 系统提示弹窗
exports.createNotifierCallback = () => {
  const notifier = require('node-notifier')

  return (severity, errors) => {
    if (severity !== 'error') return

    const error = errors[0]
    const filename = error.file && error.file.split('!').pop()

    notifier.notify({
      title: packageConfig.name,
      message: severity + ': ' + error.name,
      subtitle: filename || '',
      icon: path.join(__dirname, 'logo.png')
    })
  }
}

// ********
// 这里是我们自定义的配置

const createHtmlWebpackConfig = (template, chunkname, pluginConfig) => {
  return new HtmlWebpackPlugin({
    filename: `./${chunkname}/index.html`,
    template,
    inject: true,
    favicon: '',
    chunks: [chunkname], // 必须放在数组中,单个字符串不生效
    ...pluginConfig
  })
}
// HtmlWebpackConfig 配置
exports.getAllHtmlWebpackConfig = (pluginConfig = {}) => {
  let res = []
  Object.keys(appList).map(key => {
    const item = appList[key]
    return res.push(createHtmlWebpackConfig(config.base.pathPrefix + item.html, key, pluginConfig))
  })
  return res
}
// webpack 入口配置
exports.getEntryWebpackConfig = () => {
  let res = {}
  Object.keys(appList).map(key => {
    const item = appList[key]
    return Object.assign(res, { [key]: item.js })
  })
  return res
}

然后完善 webpack.base.conf.js 文件

// build/webpack.base.conf.js

'use strict'

const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const appList = require('../config/appList')
const { VueLoaderPlugin } = require('vue-loader')

const resolve = (dir) => {
  return path.join(__dirname, '..', dir)
}

// 根据 appList 获取 entry 的配置
const getEntryCOnfig = () => {
  const res = {}
  const rootPrefix = './src/pages'
  Object.keys(appList).map(key => {
    Object.assign(res, { [key]: `${rootPrefix}/${appList[key].js}` })
  })
  return res
}

const createLintingRule = () => ({
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})

const webpackConfig = {
  context: path.resolve(__dirname, '../'),
  entry: getEntryCOnfig(),
  output: {
    path: config.build.assetsRoot,
    filename: '[name]/[name].bundle.js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json', 'less'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          appendTsSuffixTo: [/\.vue$/],
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin()
  ],
  node: {
    setImmediate: false,
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}
module.exports = webpackConfig

更改 webpack.dev.conf.js 文件

// build/webpack.dev.conf.js

'use strict'

const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
  mode: 'development',
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'warning',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    disableHostCheck: true,
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll,
    }
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
    
    // https://github.com/ampedandwired/html-webpack-plugin
    // 这里使用我们封装的方法去生成配置
    ...(utils.getAllHtmlWebpackConfig())
  ]
})



module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
        },
        onErrors: config.dev.notifyOnErrors
        ? utils.createNotifierCallback()
        : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})

此时我们需要下面这些插件

"dependencies": {
    "axios": "^0.18.0",
    "lodash": "^4.17.11",
    "vue": "^2.5.17",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@babel/core": "^7.1.6",
    "@babel/plugin-transform-runtime": "^7.1.0",
    "@babel/preset-env": "^7.1.6",
    "@babel/runtime": "^7.1.5",
    "autoprefixer": "^9.3.1",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.4",
    "copy-webpack-plugin": "^4.6.0",
    "css-loader": "^1.0.1",
    "eslint": "^5.9.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-friendly-formatter": "^4.0.1",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^8.0.0",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^4.0.0",
    "friendly-errors-webpack-plugin": "^1.7.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.4.4",
    "node-notifier": "^5.3.0",
    "node-sass": "^4.10.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "ora": "^3.0.0",
    "portfinder": "^1.0.13",
    "postcss-import": "^12.0.1",
    "postcss-loader": "^3.0.0",
    "postcss-url": "^8.0.0",
    "rimraf": "^2.6.0",
    "sass-loader": "^7.0.3",
    "sass-resources-loader": "^2.0.0",
    "semver": "^5.3.0",
    "shelljs": "^0.8.3",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "vue-loader": "^15.4.2",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^4.25.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10",
    "webpack-merge": "^4.1.4"
  },

修改 package.json 加入环境变量

"scripts": {
    "dev": "NODE_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "NODE_ENV=production node build/build.js"
  },

终端运行

$ npm run dev

然后就可以看到熟悉的界面了
在这里插入图片描述

我们打开浏览器,在配置的端口查看页面,然后输入对应的路由
在这里插入图片描述

在这里插入图片描述

可以看到我们配置的多个入口渲染正确,且引入的 js 正确
简单修改 js 测试文件,可以看到 webpack-dev-server 运行也没有问题,可以对页面热更新

下面我们把测试的 Demo 完善,然后测试一下其他资源解析,加入 scss 和 图片资源,然后打包

在这里插入图片描述
运行没有问题,这里基本配置就完成了
线上环境的配置,主要问题集中在代码分割上,后续会详细讲解一下

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,你需要安装WebpackBabel的相关依赖包。 ``` npm install webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react --save-dev ``` 接下来,在根目录下创建一个`webpack.config.js`文件,配置WebpackBabel的相关设置。 ``` const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'] } } } ] } }; ``` 其中,`entry`指定了入口文件,`output`指定了打包后的输出路径和文件名。`module`中的`rules`是用来设置Webpack对不同类型的文件进行处理的规则。这里我们使用`babel-loader`来处理`.jsx`文件,将其转换为浏览器可读的JavaScript文件。 接下来,在`src`目录下创建一个`index.js`文件,编写一些JSX代码。 ``` import React from 'react'; import ReactDOM from 'react-dom'; const App = () => <div>Hello World!</div>; ReactDOM.render(<App />, document.getElementById('root')); ``` 最后,在`index.html`中引入打包后的`bundle.js`文件,并在页面中添加一个`id`为`root`的`div`元素。 ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack + Babel + JSX Demo</title> </head> <body> <div id="root"></div> <script src="./dist/bundle.js"></script> </body> </html> ``` 现在,运行`webpack`命令进行打包,打开`index.html`就可以看到页面中显示了`Hello World!`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值