Webpack is a powerful bundler and dependency manager used by many enterprise-level companies as tooling for their front-end code.

Webpack是一个功能强大的打包程序和依赖项管理器,许多企业级公司都将其用作前端代码的工具。

Typically, webpack is configured when a project is first set up, and small tweaks are then made to the config files as needed from time to time. Because of this, many developers don’t have a lot of experience working with webpack.

通常,Webpack是在首次设置项目时配置的,然后会根据需要不时对配置文件进行细微调整。 因此,许多开发人员没有很多使用webpack的经验。

In this hands-on tutorial, we’ll go through the basics of setting up your very own production-ready webpack config using webpack 4. We’ll discuss output management, asset management, dev and prod configs, Babel, minification, cache busting, and more.

在本动手教程中,我们将介绍使用webpack 4设置自己的可用于生产环境的webpack配置的基础知识。我们将讨论输出管理,资产管理,开发和产品配置,Babel,最小化,缓存清除, 和更多。

Let's get started!

让我们开始吧!

演示应用 (Demo App)

For the purposes of this demo, we'll be setting up a webpack config from scratch using webpack 4. Our app will just use vanilla JavaScript so that we don't get bogged down with any framework-specific details. The actual app code will be pretty small so that we can focus more on webpack.

出于本演示的目的,我们将使用webpack 4从头开始设置webpack配置。我们的应用程序将仅使用原始JavaScript,这样我们就不会陷入任何特定于框架的细节。 实际的应用程序代码将很小,因此我们可以将更多精力放在webpack上。

If you'd like to follow along, all of the code in this article can be found in GitHub. The starting point is found here, and the finished result is found here.

如果您想继续,可以在GitHub中找到本文中的所有代码。 在这里找到起点,在这里找到 完成的结果 。

初始点 (Starting Point)

To begin, we'll start out with just a few files in our project directory. The directory structure looks like this:

首先,我们将从项目目录中的几个文件开始。 目录结构如下所示:

webpack-demo|_ src|_ index.js|_ .gitignore|_ index.html|_ package.json|_ README.md|_ yarn.lock

The index.html file is nice and simple, just a page header and a script tag:

index.html文件非常简单,只有页面标题和script标签:

<!doctype html>
<html><head><title>Webpack Training 1</title></head><body><h1>Webpack Training 1</h1><script src="./src/index.js"></script></body>
</html>

The script tag references our ./src/index.js file, which has just a few lines of JavaScript in it that outputs the text, "Hello from webpack!":

script标记引用了我们的./src/index.js文件,该文件中只有几行JavaScript,它会输出文本“ Hello from webpack!”:

const p = document.createElement('p')
p.textContent = 'Hello from webpack!'
document.body.append(p)

If you drag the index.html file into your browser, you should be able to view our simple web page:

如果将index.html文件拖到浏览器中,则应该能够查看我们的简单网页:



安装依赖项 (Install Dependencies)

I've included webpack and webpack-cli as devDependencies in the package.json file.

我已经将webpackwebpack-cli作为devDependenciespackage.json文件中。

To install those, run:

要安装它们,请运行:

yarn install

Webpack测试运行 (Webpack Test Run)

Webpack 4 is set up as a "zero config" tool, meaning that you can run it out of the box without doing any initial configuration. Now, for any real project you will need to do some configuration, but it's nice that you can at least do a quick sanity check to ensure that webpack is able to run without having to go through a bunch of initial configuration steps.

Webpack 4被设置为“零配置”工具,这意味着您可以直接使用它,而无需进行任何初始配置。 现在,对于任何实际项目,您需要进行一些配置,但是很好的是,您至少可以进行快速的健全性检查,以确保webpack能够运行而无需执行许多初始配置步骤。

So, let's check it out. Run:

因此,让我们检查一下。 跑:

yarn webpack

You should now see a dist directory created in your project directory. And inside it you should see a main.js file, which is our minified code.

现在,您应该在项目目录中看到一个dist目录。 在其中,您应该看到一个main.js文件,这是我们的main.js代码。

Great! Webpack appears to be working.

大! Webpack似乎正在运行。

参考输出代码 (Reference the Output Code)

OK, now that we have JavaScript code in our dist directory, let's have our index.html file reference that. Instead of the script tag looking like this:

好的,既然我们在dist目录中有JavaScript代码,那么让我们的index.html文件引用它。 代替如下所示的script标签:

<script src="./src/index.js"></script>

Let's change it to this:

让我们将其更改为:

<script src="./dist/main.js"></script>

Now, refresh the page in your browser, and you should still see the exact same output, only this time the "Hello from webpack!" text is being generated by the ./dist/main.js file now.

现在,在浏览器中刷新页面,您仍然应该看到完全相同的输出,只是这次是“ Webpack的Hello!”。 ./dist/main.js文件现在正在生成文本。

创建一个Webpack配置文件 (Create a Webpack Config File)

Now that we have webpack installed and have gone through a quick sanity check exercise, let's create an actual webpack config file. Create a file called webpack.config.js and place the following code inside it:

现在我们已经安装了webpack并进行了快速的健全性检查练习,让我们创建一个实际的webpack配置文件。 创建一个名为webpack.config.js的文件,并将以下代码放入其中:

const path = require('path')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')}
}

The entry property tells webpack where our source code is located. It is the "entry point" for our app.

entry属性告诉webpack我们的源代码在哪里。 这是我们应用程序的“入口点”。

The output property tells webpack what to call the output file and which directory to place it in.

output属性告诉webpack如何调用输出文件以及将其放置在哪个目录中。

Simple enough, right?

很简单,对不对?

Now let's create an npm script in our package.json file:

现在,让我们在package.json文件中创建一个npm脚本:

"scripts": {"build": "webpack --config=webpack.config.js"
}

Now we can run our build process with the command yarn build. Go ahead and run that command to verify you have things set up properly. You could even delete your dist directory prior to running the yarn build command to verify that the directory is being generated.

现在,我们可以使用命令yarn build运行构建过程。 继续并运行该命令以验证是否已正确设置。 您甚至可以在运行yarn build命令之前删除dist目录,以验证是否正在生成目录。

更改输出文件名 (Change the Output File Name)

Now, just for fun, let's change the output file name. To do this, we'll open up our webpack.config.js file and change the output property from this:

现在,只是为了好玩,让我们更改输出文件名。 为此,我们将打开webpack.config.js文件,并webpack.config.js更改output属性:

output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')
}

To this:

对此:

output: {filename: 'tacos.js',path: path.resolve(__dirname, 'dist')
}

Now run yarn build again to generate the output. You should see a tacos.js file in your dist directory now.

现在再次运行yarn build来生成输出。 您现在应该在dist目录中看到tacos.js文件。

But wait! We also see the old main.js file in our dist directory too! Wouldn't it be nice if webpack could delete the old unneeded output each time we do a new build?

可是等等! 我们还在dist目录中也看到了旧的main.js文件! 如果webpack每次执行新的构建时都可以删除旧的不需要的输出,那不是很好吗?

There's got to be a plugin for that.

必须有一个插件。

Webpack插件 (Webpack Plugins)

Webpack has a rich ecosystem of modules called "plugins", which are libraries that can modify and enhance the webpack build process. We'll explore a handful of helpful plugins as we continue to improve our webpack config throughout the rest of this article.

Webpack拥有丰富的模块生态系统,称为“ 插件 ”,这是可以修改和增强Webpack构建过程的库。 我们将在本文的其余部分中继续改进Webpack的配置,探索一些有用的插件。

CleanWebpack插件 (CleanWebpackPlugin)

OK, back to our problem. It'd be nice if we could clean up the dist directory before each new build. There's a plugin for that!

好,回到我们的问题。 如果我们能在每次新构建之前清理dist目录,那就太好了。 有一个插件!

We can use the CleanWebpackPlugin to help us here. First, we need to install it in our project:

我们可以使用CleanWebpackPlugin在这里帮助我们。 首先,我们需要在项目中安装它:

yarn add --dev clean-webpack-plugin

To use it, we'll simply require the plugin in our webpack.config.js file and then include it in the plugins array in our config setup:

要使用它,我们只requirewebpack.config.js文件中插入插件,然后在配置设置中将其包含在plugins数组中:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin()]
}

Now run yarn build again, and you should see only a single output file in your dist directory. Problem solved!

现在再次运行yarn build ,您应该在dist目录中仅看到一个输出文件。 问题解决了!

HTMLWebpack插件 (HTMLWebpackPlugin)

One other thing that's a little annoying with our setup is that any time we change the output file name in our webpack.config.js file, we also have to change that file name we reference in our script tag in our index.html file. Wouldn't it be nice if webpack could manage that for us?

设置中的另一件令人讨厌的事情是,每当我们更改webpack.config.js文件中的output文件名时,我们还必须更改index.html文件中的script标记中引用的文件名。 如果webpack可以为我们管理这不是很好吗?

There's a plugin for that! We can use the HTMLWebpackPlugin to help us manage our HTML file. Let's install it in our project now:

有一个插件! 我们可以使用HTMLWebpackPlugin帮助我们管理HTML文件。 让我们现在将其安装在我们的项目中:

yarn add --dev html-webpack-plugin

Now let's move our index.html file inside our src directory so that it's a sibling to the index.js file.

现在,让我们将index.html文件移动到src目录中,以便它成为index.js文件的同级文件。

webpack-demo|_ src|_ index.html|_ index.js|_ .gitignore|_ package.json|_ README.md|_ yarn.lock

We can also delete the script tag in our index.html file since we'll have webpack handle inserting the appropriate script tag for us. Delete that line so that your index.html file looks like this:

我们也可以删除index.html文件中的script标签,因为我们将使用webpack句柄为我们插入适当的script标签。 删除该行,以便您的index.html文件如下所示:

<!doctype html>
<html><head><title>Webpack Training 1</title></head><body><h1>Webpack Training 1</h1></body>
</html>

Now let's require this plugin in our webpack.config.js file and then include it in the plugins array in our config setup, just like we did for the first plugin:

现在,让我们在webpack.config.js文件中require此插件,然后将其包含在配置设置中的plugins数组中,就像我们对第一个插件所做的那样:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),]
}

In those options for the HtmlWebpackPlugin, we specify the filename for what we'd like the output file to be called.

在对这些选项HtmlWebpackPlugin ,我们指定filename ,因为我们想什么输出文件被调用。

We specify for inject that we would like our JavaScript file to be injected into the body tag by setting the value to true.

通过将值设置为true ,我们为inject指定我们希望将JavaScript文件注入到body标签中。

And finally, for the template we supply the location of our index.html file in the src directory.

最后,对于template ,我们在src目录中提供了index.html文件的位置。

完整性检查 (Sanity Check)

OK, let's make sure everything is still working properly. Run yarn build, and verify that you see two files in your dist directory: index.html and main.js.

好的,让我们确保一切仍然正常运行。 运行yarn build ,并验证是否在dist目录中看到两个文件: index.htmlmain.js

If you look closely in your index.html file, you'll see the main.js file referenced.

如果您仔细查看index.html文件,将会看到所引用的main.js文件。

Now, open the ./dist/index.html file in your browser to verify that your page loads correctly. If you followed these steps correctly, your page should still be working:

现在,在浏览器中打开./dist/index.html文件,以验证页面是否正确加载。 如果您正确执行了这些步骤,则您的页面仍将正常工作:

创建开发服务器 (Create a Development Server)

We've made some good improvements so far using the CleanWebpackPlugin and the HtmlWebpackPlugin. As we've made these changes, we've had to manually run the yarn build command each time to see new changes in our app. We've also just been viewing the file in our browser rather than viewing the content served from a server running locally. Let's improve our process by creating a development server.

到目前为止,我们使用CleanWebpackPluginHtmlWebpackPlugin进行了一些改进。 完成这些更改后,每次必须手动运行yarn build命令才能在应用程序中查看新更改。 我们也只是在浏览器中查看文件,而不是查看本地运行的服务器提供的内容。 让我们通过创建开发服务器来改进流程。

To do this, we'll use webpack-dev-server. First, we'll need to install it:

为此,我们将使用webpack-dev-server 。 首先,我们需要安装它:

yarn add --dev webpack-dev-server

Now, let's split up our single webpack.config.js file into two separate config files, one for production and one for development. We'll call the file for production webpack.config.prod.js and the file for development webpack.config.dev.js.

现在,让我们将单个webpack.config.js文件拆分为两个单独的配置文件,一个用于生产,一个用于开发。 我们将其称为生产webpack.config.prod.js的文件,并将其webpack.config.dev.js开发webpack.config.dev.js的文件。

开发Webpack配置 (Development Webpack Config)

Here's our development config file:

这是我们的开发配置文件:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {mode: 'development',devtool: 'inline-source-map',devServer: {contentBase: './dist',},entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),]
}

Note that we've specified the mode as development now, and we've specified that we would like an inline-source-map for our JavaScript files, meaning that a source map is included at the end of each JavaScript file. For our dev server, we've specified that our content will be found in the dist directory.

请注意,我们现在已将mode指定为development mode ,并且已指定我们想要JavaScript文件的inline-source-map ,这意味着在每个JavaScript文件的末尾都包含一个源映射。 对于开发服务器,我们指定了将在dist目录中找到我们的内容。

All the rest of the development config has stayed the same.

所有其他开发配置均保持不变。

生产Webpack配置 (Production Webpack Config)

Now, here's our production config file:

现在,这是我们的生产配置文件:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {mode: 'production',devtool: 'source-map',entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),]
}

This file also looks very similar to our original config file. Here we've specified that the mode is production and that we would like the source-map option for source maps, which provides separate source map files for minified code.

该文件看起来也与我们的原始配置文件非常相似。 在这里,我们指定了modeproduction mode ,并且希望使用source-mapsource-map选项,该选项为缩小的代码提供了单独的源地图文件。

生产和开发NPM脚本 (Production and Development NPM Scripts)

Finally, let's add a few more npm scripts in our package.json file so that we can work with our development and production webpack configs:

最后,让我们在package.json文件中添加更多npm脚本,以便我们可以使用开发和生产Webpack配置:

"scripts": {"build": "webpack --config=webpack.config.prod.js","build-dev": "webpack --config=webpack.config.dev.js","start": "webpack-dev-server --config=webpack.config.dev.js --open"
}

Now, let's try out each of these scripts.

现在,让我们尝试这些脚本。

Run yarn build to see the production build output. You should see that the main.js file in your dist directory is minified and that it has an accompanying main.js.map source map file.

运行yarn build以查看生产构建输出。 您应该看到的是, main.js在文件dist目录的微细化以及它有一个伴随main.js.map源地图文件。

Now run yarn build-dev to see the development build output. You should see the main.js file in your dist directory, but now note that it is not minified.

现在运行yarn build-dev以查看开发构建输出。 您应该在dist目录中看到main.js文件,但是现在注意它没有缩小。

Lastly, run yarn start to start up the development server. This will open up the app on http://localhost:8080/. No more having to view the files directly by just pulling them into your browser! We now have a real live development server!

最后,运行yarn start启动开发服务器。 这将在http://localhost:8080/上打开该应用程序。 无需将它们直接拖到浏览器中直接查看文件! 现在,我们有一个真正的实时开发服务器!

The output you see should still look the same as it always has:

您看到的输出应该仍然与以前一样:

在开发过程中进行更改 (Making Changes During Development)

Now that we have a working dev server, let's experiment with making some simple changes to our ./src/index.js file. Instead of outputting "Hello from webpack!", let's change it to say "Hello from dev server!".

现在我们有了一个可以正常工作的开发服务器,让我们尝试对./src/index.js文件进行一些简单的更改。 与其输出“ Webpack的Hello!”,而是将其改为“开发服务器的Hello!”。

Save the file, and then see the page on your dev server automatically reload and update for you! That'll be a nice boost to your developer productivity.

保存文件,然后在开发服务器上看到页面自动为您重新加载和更新! 这将大大提高开发人员的工作效率。

不要重复自己(干) (Don't Repeat Yourself (DRY))

Now that we have two separate webpack config files, one for development and one for production, you may have noticed that we have a lot of duplicated code between the two files.

现在我们有了两个单独的webpack配置文件,一个用于开发,一个用于生产,您可能已经注意到,两个文件之间有很多重复的代码。

Every developer out there has had the DRY principle drilled into their heads since day one: Don't repeat yourself. If you find yourself writing the same code in multiple places, it may be a good idea to turn that into shared code that can be written in one place and then used in multiple places. That way when you need to make changes, you only need to implement those changes in one place.

从第一天开始,那里的每个开发人员就已经将DRY原则付诸实践:不要重复自己。 如果发现自己在多个地方编写相同的代码,则最好将其转换为可以在一个地方编写然后在多个地方使用的共享代码。 这样,当您需要进行更改时,只需要在一个地方实施这些更改即可。

So, how can we clean up the duplication in our webpack config files? There's a plugin for that!

那么,我们如何清理webpack配置文件中的重复项呢? 有一个插件!

Webpack合并 (WebpackMerge)

We can use the webpack-merge plugin to manage shared code that multiple config files rely on. To do this, we'll first install the package:

我们可以使用webpack-merge插件来管理多个配置文件所依赖的共享代码。 为此,我们将首先安装该软件包:

yarn add --dev webpack-merge

Now we'll create a third webpack config file called webpack.config.common.js. This is where we'll keep our shared code. Right now, our development and production config files share the same entry point, output, and plugins. All that differs between the two files are the mode, source map, and dev server.

现在,我们将创建第三个webpack配置文件,名为webpack.config.common.js 。 这是我们保留共享代码的地方。 现在,我们的开发和生产配置文件共享相同的入口点,输出和插件。 这两个文件之间的所有不同之处在于模式,源映射和开发服务器。

So, the contents of our webpack.config.common.js file will be:

因此,我们的webpack.config.common.js文件的内容为:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),]
}

And now, we can merge this shared config object into our development config like this:

现在,我们可以像下面这样将共享的配置对象合并到我们的开发配置中:

const merge = require('webpack-merge')
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'development',devtool: 'inline-source-map',devServer: {contentBase: './dist',},
})

And we can merge the shared config object into our production config like this:

我们可以将共享配置对象合并到生产配置中,如下所示:

const merge = require('webpack-merge')
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'production',devtool: 'source-map',
})

Look how much shorter and cleaner those two files look! Beautiful!

看看这两个文件看起来更短更干净! 美丽!

造型我们的应用程序 (Styling Our App)

Things are looking pretty good with our webpack configs so far. We have a working dev server and we've split out our code into development, production, and shared configuration files.

到目前为止,我们的webpack配置看起来一切都很好。 我们有一个工作的开发服务器,并且已经将代码分为开发,生产和共享配置文件。

Let's start working on our actual app code now. The plain black and white page is a little boring to look at. Let's style it up!

让我们立即开始实际的应用程序代码。 普通的黑白页面看起来有些无聊。 让我们来造型​​吧!

In our src directory, let's create an index.css file and place the following lines of CSS inside it:

在我们的src目录中,创建一个index.css文件,并将以下CSS行放入其中:

body {background: deeppink;color: white;
}

Then, in our ./src/index.js file, let's import that CSS file:

然后,在我们的./src/index.js文件中,导入该CSS文件:

import './index.css'

Now, run yarn start to get our development server running again.

现在,运行yarn start使我们的开发服务器再次运行。

Oh no! We get an error!

不好了! 我们得到一个错误!

ERROR in ./src/index.css 1:5
Module parse failed: Unexpected token (1:5)
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
> body {
|   background: deeppink;
|   color: white;@ ./src/index.js 1:0-20

What are these "loaders" it speaks of?

它所说的这些“装载者”是什么?

Webpack加载器 (Webpack Loaders)

Earlier, we discussed webpack plugins, which let you extend the webpack build process. There is also an ecosystem of webpack "loaders", which help webpack know how to understand and load different file types. Out of the box, webpack understands how to handle our JavaScript files, but it doesn't know what to do with CSS files yet. Let's fix that.

之前,我们讨论了webpack插件,这些插件使您可以扩展webpack的构建过程。 还有一个webpack“ 加载程序 ”生态系统,它可以帮助webpack知道如何理解和加载不同的文件类型。 webpack开箱即用,可以理解如何处理我们JavaScript文件,但是尚不知道如何处理CSS文件。 让我们修复它。

StyleLoader和CSSLoader (StyleLoader and CSSLoader)

There are two loaders in particular that will be helpful for us here: style-loader and css-loader. Let's get those included in our project and then discuss how they work.

这里有两个特别对我们有用的加载器 : style-loader和css-loader 。 让我们将它们包含在我们的项目中,然后讨论它们如何工作。

To start, as always, we'll need to install those two dependencies:

与往常一样,我们首先需要安装这两个依赖项:

yarn add --dev style-loader css-loader

Then we can add them to our webpack.config.common.js file in the module rules section down at the bottom:

然后,我们可以将它们添加webpack.config.common.js部底部模块规则部分的webpack.config.common.js文件中:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),],module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']}]}
}

This section sets up rules for webpack so it knows what to do with each file it encounters. The test property is a regular expression that webpack checks against the file name. In this case, we want to handle files with a .css extension.

本节为webpack设置规则,以便知道如何处理遇到的每个文件。 test属性是一个正则表达式,Webpack会根据文件名进行检查。 在这种情况下,我们要处理扩展名为.css文件。

Then, the use property tells webpack what loader or loaders to use to handle files matching the criteria. Note that the order here matters!

然后, use属性告诉webpack use哪些加载程序来处理符合条件的文件。 请注意,这里的顺序很重要!

Webpack loaders are read from right to left. So first the css-loader will be applied, and then the style-loader will be applied.

Webpack加载程序从右到左读取。 因此,首先将应用css-loader ,然后将应用style-loader

Now, what do these loaders actually do for us?

现在,这些装载机实际上对我们有什么作用?

css-loader interprets and resolves imported CSS files that you reference in your JavaScript. So in this case, css-loader helps make this line work:

css-loader解释并解析您在JavaScript中引用的导入CSS文件。 因此,在这种情况下, css-loader可帮助使此行正常工作:

import './index.css'

Next, style-loader injects the CSS into the DOM. By default, style-loader takes the CSS it encounters and adds it to the DOM inside a style tag.

接下来, style-loader将CSS注入DOM。 默认情况下, style-loader会获取遇到CSS,并将其添加到style标签内的DOM中。

Let's restart our dev server by killing the current process (if you still have it running) and then starting it again with yarn start. Now, in the web browser, you should see this on https://localhost:8080/:

让我们通过终止当前进程(如果仍在运行)来重新启动开发服务器,然后使用yarn start再次启动它。 现在,在Web浏览器中,您应该在https://localhost:8080/上看到它:

Oooh, so colorful!

噢,好多彩!

有关其他Webpack加载程序的说明 (A Note on Other Webpack Loaders)

We won't cover loaders for other file types in this article, but be aware that there's a loader for everything imaginable! You can use file-loader or url-loader for loading images and other assets. You can use sass-loader to handle converting Sass/SCSS files to CSS before piping that output to css-loader and style-loader. Webpack can handle Less files too with less-loader if that's your preference.

我们不会在本文中介绍其他文件类型的加载程序,但是请注意,可以想象的一切都有一个加载程序! 您可以使用文件加载器或url加载器来加载图像和其他资产。 您可以使用sass-loader将Sass / SCSS文件转换为CSS,然后再将其输出到css-loaderstyle-loader 。 如果您愿意,Webpack也可以使用更少的加载器来处理更少的文件。

The moral of the story is: For any given file type, there's a loader that can handle it.

这个故事的寓意是:对于任何给定的文件类型,都有一个可以处理它的加载器。

BabelLoader (BabelLoader)

Ok, back to our demo app. We've written just a few lines of JavaScript so far. It'd be nice if we could write our JavaScript using new features that aren't well-supported in every browser yet. Babel is a JavaScript compiler that can turn ES6+ code into ES5 code.

好的,回到我们的演示应用程序。 到目前为止,我们仅编写了几行JavaScript。 如果我们可以使用尚未在每个浏览器中都得到很好支持的新功能来编写JavaScript,那就太好了。 Babel是一个JavaScript编译器,可以将ES6 +代码转换为ES5代码。

And (you guessed it), there's a loader for that: babel-loader.

而且(您猜对了),有一个加载器用于: babel-loader 。

To set up babel-loader, we'll follow the instructions on their installation guide linked above.

要设置babel-loader ,我们将按照上面链接的安装指南中的说明进行操作。

First, we'll install our dependencies:

首先,我们将安装依赖项:

yarn add --dev babel-loader @babel/core

Next, we'll add a new rule to our module rules array in our webpack.config.common.js file:

接下来,我们将在webpack.config.common.js文件中的模块规则数组中添加新规则:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),],module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']},{test: /\.(js|jsx)$/,exclude: /[\\/]node_modules[\\/]/,use: {loader: 'babel-loader',},},]}
}

This will tell webpack that when it encounters .js or .jsx files to use Babel to transform the code. We use the exclude property to make sure Babel doesn't try to transform JavaScript files in our node_modules directory. Those are third-party dependencies that should already have been taken care of by their creators.

这将告诉webpack在遇到.js.jsx文件时使用Babel转换代码。 我们使用exclude属性来确保Babel不会尝试转换node_modules目录中JavaScript文件。 这些是第三方依赖关系,其创建者应该已经解决了。

Next, we'll add one more dependency for a Babel preset:

接下来,我们将为Babel预设添加一个依赖项:

yarn add --dev @babel/preset-env

And then we'll create a .babelrc file where we can do other Babel configuration as needed. We'll keep our file pretty simple and just specify the Babel preset that we want to use:

然后,我们将创建一个.babelrc文件,可以根据需要进行其他Babel配置。 我们将使文件保持非常简单,仅指定我们要使用的Babel预设:

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

And finally, let's write some ES6 code in our ./src/index.js file:

最后,让我们在./src/index.js文件中编写一些ES6代码:

import './index.css'const p = document.createElement('p')
p.textContent = 'Hello from webpack!'
document.body.appendChild(p)const p2 = document.createElement('p')
const numbers1 = [1, 2, 3, 4, 5, 6]
const numbers2 = [7, 8, 9, 10]
const numbers3 = [...numbers1, ...numbers2]
p2.textContent = numbers3.join(' ')
document.body.appendChild(p2)

This is a really trivial example, but we're using the spread operator here to concatenate two arrays.

这是一个非常简单的示例,但是我们在这里使用了散布运算符来连接两个数组。

Now, if we kill our running process and run yarn start again, we should see this in the browser:

现在,如果我们终止正在运行的进程并再次运行yarn start ,我们应该在浏览器中看到以下内容:

Great! Everything is working nicely.

大! 一切都很好。

暂时缺少样式 (Temporarily Missing Styles)

If you disable the cache in your browser and reload the page for our demo app, you may notice a slight blip in which the page appears with just the un-styled HTML, and then the page background turns pink and the text turns white as the styles are applied.

如果您在浏览器中禁用了缓存并重新加载了演示应用程序的页面,您可能会注意到一个轻微的斑点,其中页面仅显示未设置样式HTML,然后页面背景变为粉红色,文本变为白色,应用样式。

This behavior results from how style-loader works. As mentioned above, style-loader takes CSS and places it in a style tag in your HTML. Because of that, there's a brief period of time in which the style tag hasn't been appended yet!

此行为是由style-loader工作原理引起的。 如上所述, style-loader CSS并将其放在HTML的style标签中。 因此,有一小段时间尚未添加style标签!

Now, this is OK for a development environment, but we definitely wouldn't want this kind of behavior occurring in production. Let's fix that.

现在,这对于开发环境是可以的,但我们绝对不希望在生产中发生这种行为。 让我们修复它。

MiniCssExtractPlugin (MiniCssExtractPlugin)

Rather than injecting CSS into our HTML as style tags, we can use the MiniCssExtractPlugin to generate separate CSS files for us. We'll use this in our production config while still just using style-loader in our development config.

可以使用MiniCssExtractPlugin为我们生成单独CSS文件,而不是将CSS作为style标签注入HTML。 我们将在生产配置中使用它,而仍然在开发配置中使用style-loader

First, let's install the dependency in our project:

首先,让我们在项目中安装依赖项:

yarn add --dev mini-css-extract-plugin

Now in our webpack.config.common.js file let's remove the CSS rule since we'll be handling this differently in development and production. We're left with this in our shared config:

现在,在我们的webpack.config.common.js文件中,让我们删除CSS规则,因为在开发和生产中我们将对此进行不同的处理。 我们在共享配置中保留了以下内容:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),],module: {rules: [{test: /\.(js|jsx)$/,exclude: /[\\/]node_modules[\\/]/,use: {loader: 'babel-loader',},},]}
}

Now, in our webpack.config.dev.js file, let's add back in style-loader and css-loader that we just removed from our shared config:

现在,在webpack.config.dev.js文件中,让我们webpack.config.dev.js添加刚刚从共享配置中删除的style-loadercss-loader

const merge = require('webpack-merge')
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'development',devtool: 'inline-source-map',devServer: {contentBase: './dist',},module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']},]}
})

And finally, in our webpack.config.prod.js file, let's add in our new mini-css-extract-plugin:

最后,在我们的webpack.config.prod.js文件中,让我们添加新的mini-css-extract-plugin

const merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'production',devtool: 'source-map',module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader',],},],},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',}),]
})

This one is a little different because it actually is both a plugin and a loader, so it goes in the module rules and in the plugins sections.

这个有点不同,因为它实际上既是一个插件是一个加载器,因此它出现在模块规则和插件部分中。

Also note that we use the square brackets in our file name to dynamically set the name to the original source file's name and also include the contenthash, which is a hash (an alphanumeric string) that represents the file's contents.

另外请注意,我们使用了方括号在我们的文件名的动态设置name为原始源文件的名称,还包括contenthash ,这是一个散列(字母数字字符串),表示该文件的内容。

Now if you run yarn build this time to generate the production build, you should get some output in your terminal that looks like this:

现在,如果您这次运行yarn build来生成生产版本,则应该在终端中获得一些输出,如下所示:

Note that it actually generates a CSS file now, and the content hash is included in the file name.

请注意,它实际上现在会生成一个CSS文件,并且内容哈希包含在文件名中。

Alright, problem solved! No more blip when the page loads in production since we have the styles included as a link tag to an actual CSS file.

好了,问题解决了! 当页面在生产环境中加载时,不再出现任何问题,因为我们将样式包含为link实际CSS文件的link标记。

快取清除 (Cache Busting)

Since we've included the content hash in the generated CSS file, now is a good time to talk about cache busting. Why, you ask, would we want the content hash included in our file names? To help the browser understand when a file has changed!

由于我们已经在生成CSS文件中包括了内容哈希,因此现在是讨论缓存清除的好时机。 您问为什么要在文件名中包含内容哈希? 帮助浏览器了解文件更改的时间!

Your browser tries to be helpful by caching files it has seen before. For example, if you've visited a website, and your browser had to download assets like JavaScript, CSS, or image files, your browser may cache those files so that it doesn't have to request them from the server again.

您的浏览器试图通过缓存以前见过的文件来提供帮助。 例如,如果您访问了一个网站,并且浏览器必须下载JavaScript,CSS或图像文件之类的资产,则您的浏览器可能会缓存这些文件,从而不必再次从服务器请求它们。

This means that if you visit the site again, your browser can use the cached files instead of requesting them again, so you get a faster page load time and a better experience.

这意味着,如果您再次访问该站点,您的浏览器可以使用缓存的文件,而不必再次请求它们,因此您可以获得更快的页面加载时间和更好的体验。

So, what's the problem here? Imagine if we had a file called main.js used in our app. Then, a user visits your app and their browser caches the main.js file.

那么,这是什么问题呢? 假设我们的应用程序中有一个名为main.js的文件。 然后,用户访问您的应用程序,并且他们的浏览器缓存main.js文件。

Now, at some later point in time, you've released new code for your app. The contents of the main.js file have changed. But, when this same user visits your app again, the browser sees that it needs a main.js file, notes that it has a cached main.js file, and just uses the cached version. The user doesn't get your new code!

现在,在稍后的某个时间点,您已经为您的应用发布了新代码。 main.js文件的内容已更改。 但是,当同一用户再次访问您的应用程序时,浏览器会发现它需要一个main.js文件,并注意到它具有一个已缓存的main.js文件,并且仅使用了该版本。 用户没有得到您的新代码!

To solve this problem, a common practice is to include the content hash in each file's name. As discussed earlier, the content hash is a string representation of the file's contents. If the file's contents don't change, the content hash doesn't change. But, if the file's contents do change, then the content hash also changes.

为了解决此问题,通常的做法是在每个文件的名称中包含内容哈希。 如前所述,内容哈希是文件内容的字符串表示形式。 如果文件的内容不变,则内容哈希也不变。 但是,如果文件的内容确实发生了变化,则内容哈希也将发生变化。

Because the file name will now change when the code changes, the browser will download the new file since it won't have that specific file name in its cache.

因为代码更改时文件名现在会更改,所以浏览器将下载新文件,因为它的缓存中没有该特定文件名。

包括内容哈希 (Including the Content Hash)

To include the content hash in our JavaScript file names, we'll modify just one line of code in our webpack.config.common.js file. This line:

为了将内容哈希包含在我们JavaScript文件名中,我们将只修改webpack.config.common.js文件中的一行代码。 这行:

filename: 'main.js'

Will change to this line:

将更改为这一行:

filename: '[name].[contenthash].js'

So that the entire file looks like this:

这样整个文件看起来像这样:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {filename: '[name].[contenthash].js', // this line is the only differencepath: path.resolve(__dirname, 'dist')},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({filename: 'index.html',inject: true,template: path.resolve(__dirname, 'src', 'index.html'),}),],module: {rules: [{test: /\.(js|jsx)$/,exclude: /[\\/]node_modules[\\/]/,use: {loader: 'babel-loader',},},]}
}

Now if you run yarn build, you'll see that both your JavaScript and your CSS have content hashes included:

现在,如果运行yarn build ,您将看到JavaScript和CSS都包含内容哈希:

If you run yarn build again and compare your new output to your old output, you'll notice that the content hashes are exactly the same both times.

如果再次运行yarn build并将新输出与旧输出进行比较,您会发现内容哈希值两次完全相同。

But, if you edit your ./src/index.js file in any way and then run yarn build again, you'll get a new content hash because the content has changed! Try it!

但是,如果您以任何方式编辑./src/index.js文件,然后再次运行yarn build ,您将得到一个新的内容哈希,因为内容已更改! 试试吧!

缩小CSS (Minifying CSS)

Last but not least, we may want to minify our CSS. We're already minifying our JavaScript for the production build, but we're not minifying our CSS yet. Let's do that.

最后但并非最不重要的一点是,我们可能要缩小CSS。 我们已经在生产版本中最小化了JavaScript,但是还没有最小化CSS。 来做吧。

We can minimize our CSS by using the optimize-css-assets-webpack-plugin. Let's install that dependency now:

我们可以通过使用optimize-css-assets-webpack-plugin最小化CSS。 现在安装该依赖项:

yarn add --dev optimize-css-assets-webpack-plugin

Now we can add that to an optimization section of our webpack.config.prod.js file:

现在,我们可以将其添加到webpack.config.prod.js文件的优化部分:

const merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'production',devtool: 'source-map',module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader',],},],},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',}),],optimization: {minimizer: [new OptimizeCssAssetsPlugin({cssProcessorOptions: {map: {inline: false,annotation: true,},},}),],},
})

Now if we run yarn build and then check out the contents of our dist directory, we can see that the resulting CSS is minified. Nice!

现在,如果我们运行yarn build ,然后检查dist目录的内容,我们可以看到生成CSS已缩小。 真好!

body{background:#ff1493;color:#fff}
/*# sourceMappingURL=main.66e0d6aeae6f3c6fb895.css.map */

But wait! If we look at our resulting JavaScript file, it's not minified! Hmmm. It was minified before, so what happened here?

可是等等! 如果我们查看生成JavaScript文件,那么它没有缩小! 嗯 之前已经缩小了,所以这里发生了什么?

The issue is that we're now manually configuring the optimization minimizer section of our webpack config. When that section isn't in the webpack config file, webpack defaults to using its own minimizer preferences, which includes minifying JavaScript when the mode is set to production.

问题是我们现在正在手动配置webpack配置的优化最小化器部分。 如果该部分不在webpack配置文件中,则webpack默认使用其自己的最小化器首选项,其中包括将mode设置为production时最小化JavaScript。

Since we're now overriding those defaults by adding in our preferences for minifying CSS assets, we'll need to also explicitly include instructions for how we want webpack to minify JavaScript assets.

由于我们现在通过添加用于最小化CSS资产的首选项来覆盖这些默认值,因此,我们还需要明确包含有关如何使webpack最小化JavaScript资产的说明。

TerserWebpack插件 (TerserWebpackPlugin)

We can minify our JavaScript files using the TerserWebpackPlugin. Let's start by installing that dependency:

我们可以使用TerserWebpackPlugin缩小JavaScript文件。 让我们从安装该依赖关系开始:

yarn add --dev terser-webpack-plugin

Then, in our webpack.config.prod.js file, let's add the terser-webpack-plugin to our optimization minimizer settings at the bottom of the file:

然后,在我们的webpack.config.prod.js文件中,将terser-webpack-plugin到文件底部的优化最小化器设置中:

const merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const commonConfig = require('./webpack.config.common')module.exports = merge(commonConfig, {mode: 'production',devtool: 'source-map',module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader',],},],},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',}),],optimization: {minimizer: [new OptimizeCssAssetsPlugin({cssProcessorOptions: {map: {inline: false,annotation: true,},},}),new TerserPlugin({// Use multi-process parallel running to improve the build speed// Default number of concurrent runs: os.cpus().length - 1parallel: true,// Enable file cachingcache: true,sourceMap: true,}),],},
})

Now if we run yarn build and look at the output in the dist directory, we should see that both our CSS files and our JavaScript files are minified. There we go!

现在,如果我们运行yarn build并查看dist目录中的输出,我们应该看到CSS文件和JavaScript文件都已缩小。 好了!

结语 (Wrapping Up)

If you've followed along this far, I commend you!

如果您一直遵循这一原则,我向您表示赞赏!

Let's review what we've learned so far:

让我们回顾一下到目前为止所学到的东西:

  • Webpack is a build tool for asset bundling and dependency management.Webpack是用于资产捆绑和依赖管理的构建工具。
  • Webpack can be configured by a config file.Webpack可以通过配置文件进行配置。
  • Plugins modify and extend the webpack build process.插件会修改并扩展Webpack的构建过程。
  • Loaders instruct webpack how to handle different file types.加载程序指示webpack如何处理不同的文件类型。
  • The clean-webpack-plugin can be used to remove old build artifacts from the dist directory.

    clean-webpack-plugin可用于从dist目录中删除旧的构建工件。

  • The html-webpack-plugin helps manage the HTML file, including injecting JavaScript into the file via script tags.

    html-webpack-plugin有助于管理HTML文件,包括通过script标签将JavaScript注入文件中。

  • webpack-dev-server creates a dev server to make local development easier.

    webpack-dev-server创建一个dev服务器来webpack-dev-server本地开发。

  • It's helpful to have separate webpack configs for development and production. You can share and merge config files using the webpack-merge plugin.

    为开发和生产使用单独的webpack配置很有帮助。 您可以使用webpack-merge插件共享和合并配置文件。

  • We can handle styling our app by including loaders like css-loader, style-loader, sass-loader, less-loader, and the mini-css-extract-plugin (which functions as both a plugin and a loader).

    我们可以通过包含css-loaderstyle-loadersass-loaderless-loadermini-css-extract-plugin (既充当插件又充当加载器)之类css-loader来处理应用css-loader style-loader

  • We can include new JavaScript syntax and features by using Babel and babel-loader.

    我们可以使用Babel和babel-loader来包含新JavaScript语法和功能。

  • We can include content hashes in our file names to help with cache busting and managing new versions of our released code.我们可以在文件名中包含内容哈希,以帮助清除缓存和管理已发布代码的新版本。
  • We can minify our CSS with the optimize-css-assets-webpack-plugin.

    我们可以使用optimize-css-assets-webpack-plugin最小optimize-css-assets-webpack-plugin

  • We can minify our JavaScript with the terser-webpack-plugin.

    我们可以使用terser-webpack-plugin缩小JavaScript。

下一步是什么? (What's Next?)

Throughout this article, we've created a pretty respectable webpack config. All of these techniques we've discussed are industry standards and are common to use in enterprise-level projects.

在本文中,我们已经创建了一个非常受人尊敬的webpack配置。 我们讨论的所有这些技术都是行业标准,在企业级项目中很常见。

But there's still more! Other advanced webpack topics include code splitting, lazy loading, tree shaking, and more!

但是还有更多! 其他高级Webpack主题包括代码拆分 , 延迟加载 , 摇树等等!

If you're interested in exploring webpack more on your own, I'd highly recommend reading through the official webpack guides.

如果您有兴趣自行探索Webpack,强烈建议您阅读官方Webpack指南 。

Again, all of the code we've gone through in this tutorial can be found in GitHub. The starting point is found here, and the finished result is found here.

同样,可以在GitHub上找到我们在本教程中学习过的所有代码。 在这里找到起点,在这里找到 完成的结果 。

Thanks for reading, and happy coding!

感谢您的阅读,并祝您编程愉快!

翻译自: https://www.freecodecamp.org/news/creating-a-production-ready-webpack-4-config-from-scratch/

如何从头开始创建可用于生产环境的Webpack 4配置相关推荐

  1. 一台服务器创建多个ssh_如何创建可用于生产的第一台安全服务器

    一台服务器创建多个ssh by Flavio H. Freitas Flavio H.Freitas着 如何创建可用于生产的第一台安全服务器 (How to create your first saf ...

  2. 生产环境 Apache 和 php 配置优化(一)

    2019独角兽企业重金招聘Python工程师标准>>> 多处理模块(MPM) Apache HTTP 服务器被设计为一个功能强大,并且灵活的 web 服务器, 可以在很多平台与环境中 ...

  3. 【案例】加文医学研究所计划部署 OpenStack 用于生产环境

    导读 澳大利亚加文医学研究所正在准备使用基于 OpenStack 的私有云来帮助研究人员提升效率. 加文医学研究所HPC高级工程师 Manuel Ballesteros 表示,该研究所正在关注如何使用 ...

  4. mysql差异备份实现_结合Git实现Mysql差异备份,可用于生产环境

    埋头苦干多年一直没写过文章,今天突发狂想,为LNMP阵营贡献一些力量.就从平时工作过程中的心得和一些技巧分享出来.今天就猿们最熟悉的Mysql开始宅鸟的开篇博客文章.欢迎猿们拍砖.转载. 注意:宅鸟的 ...

  5. git mysql差异备份_结合Git实现Mysql差异备份,可用于生产环境

    埋头苦干多年一直没写过文章,今天突发狂想,为LNMP阵营贡献一些力量.就从平时工作过程中的心得和一些技巧分享出来.今天就猿们最熟悉的Mysql开始宅鸟的开篇博客 埋头苦干多年一直没写过文章,今天突发狂 ...

  6. Oracle官文,明确20c不能用于生产环境

    Oracle数据库20c仅可用于预览.它不能用于生产.不支持升级到或从Oracle数据库20c升级.

  7. CMS:听我的,生产环境上要这样配置JVM参数

    哪怕JDK16 GA已经发布很久了,但是,可以肯定的是,绝大多数的生产环境依然运行的是JDK8.此处必须来一句:JDK8 yyds.既然运行的是JDK8,那么生产环境的垃圾回收器基本上就是下面3种啦: ...

  8. 生产环境JVM内存大小配置

    对于Java8而言,堆内存的初识容量为机器实际内存大小的1/64, 最大内存不超过机器实际内存的1/4. 我们的生产环境一般最大4G内存是上限了,这个视具体业务而定,流量大的互联网公司单机内存占用超过 ...

  9. 浏览器允许跨域设置(不用于生产环境,开发用)

    Firefox 之前看过FF下关闭跨域限制的方法: firefox安全性强,不允许跨域调用.Firefox 要取消XMLHttpRequest的跨域限制的话 从 about:config 里设置 si ...

  10. java订单编号生产代码,java 订单编号 生成器,可用于生产环境

    1.订单头/** 订单类别头 */ private static final String ORDER_CODE = "1"; /** 退货类别头 */ private stati ...

最新文章

  1. WPF 快速制作可拖拽的对象和窗体
  2. 【BZOJ】1031: [JSOI2007]字符加密Cipher(后缀数组)
  3. 微服务架构如何保证安全性?
  4. Unity3dShader_边缘发光效果
  5. antd vue 树更新数据后不展开_很全面的vue面试题总结
  6. 反序列化层遍历二叉树
  7. 让CentOS能用yum自动安装rar和unrar
  8. Pointers On C 1
  9. JAVA入门级教学之(while循环语句)
  10. BZOJ1862: [Zjoi2006]GameZ游戏排名系统
  11. Tomcat starup.bat脚本开机自启动
  12. Jenkins驱动SeleniumGrid测试
  13. FlexSim仿真软件入门笔记:基本操作、快捷键
  14. python Gstreamer 播放不同编码格式的视频文件
  15. 3dmax软件渲染模型导出JPG格式图片的方法
  16. 可解释性神经网络——3.一种新的可解释性神经网络GAMI-Net
  17. mc 手游无限挑战服务器,新版本的诱惑 弹弹堂手游无限挑战你敢来吗
  18. matplotlib调整线段颜色、粗细、样式(虚线)、标签字号、xy轴序号和标签字号大小
  19. HFSS学习笔记——T型波导
  20. 往mysql批量插入datetime

热门文章

  1. 考研政治---马克思主义基本原理概论---认识论
  2. ant design + react带有二级导航菜单自动生成
  3. UVa 106 Fermat vs. Pythagoras(毕达哥拉斯定理)
  4. CSDN愈来愈金钱化
  5. 二维码:MP3音频世界的进化
  6. 数据结构与算法分析----顺序表
  7. FTP服务器是什么意思
  8. atom平台 android ia,ZTE Grand X IN:搭载Atom平台的Android机
  9. 有关计算机专业的对联,有趣的电脑对联(微软亚洲研究院自然语言计算组研发)...
  10. Angular 三目运算符