我有一个带有翻译的.js文件。
translations.js
export const translations = {
common: {
search: ['Search', 'Rechercher'],
submit: ['Submit', 'Envoyer'],
reset: ['Reset', 'Réinitialiser']
}
};
export default translations;
当我在其上运行webpack build时,一切看起来都很好。但是,当我在开发服务器上执行此操作时,法语的unicode字符(例如é)将替换为“?”。
我不知道为什么在一台计算机上构建它时会添加“?”。当我关闭js uglification时,它仍然存在,因此我认为它是在babel步骤中发生的吗?
package.json
{
"name": "guests-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"serve:cold": "webpack-dev-server --inline --progress --config build/webpack.cold.conf.js",
"serve:cold-lan": "webpack-dev-server --inline --progress --config build/webpack.cold.conf.js --host 0.0.0.0",
"serve:hot": "webpack-dev-server --inline --progress --config build/webpack.hot.conf.js",
"start": "npm run serve:cold",
"test": "cross-env BABEL_ENV=test jest",
"test:watch": "cross-env BABEL_ENV=test jest --watch",
"lint": "eslint {src/**/*.js*,test/**/*.js*} && exit 0",
"lint:fix": "eslint {src/**/*.js*,test/**/*.js*} --fix && exit 0",
"posttest": "npm run lint",
"build": "node build/build.js"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint:fix"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.18.0",
"bootstrap": "^4.3.1",
"classnames": "^2.2.6",
"core-js": "^2.6.5",
"date-fns": "^2.0.0-alpha.34",
"es6-promise": "^4.2.5",
"formik": "^1.5.2",
"prop-types": "^15.6.2",
"raf": "^3.4.1",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.8",
"react-datepicker": "^2.4.0",
"react-dom": "^16.6.0",
"react-redux": "^5.1.0",
"react-select": "^2.4.3",
"react-switch": "^5.0.0",
"react-virtualized": "^9.21.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"yup": "^0.27.0"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"axios-mock-adapter": "^1.10.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.22.1",
"babel-eslint": "^7.1.1",
"babel-jest": "^23.6.0",
"babel-loader": "^7.1.1",
"babel-plugin-istanbul": "^4.1.1",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.3.2",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-preset-stage-2": "^6.22.0",
"babel-register": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.1",
"css-loader": "^0.28.0",
"enzyme": "^3.2.0",
"enzyme-adapter-react-16": "^1.1.0",
"enzyme-to-json": "^3.3.4",
"eslint": "^3.19.0",
"eslint-config-airbnb-base": "^11.3.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.7.1",
"eslint-plugin-html": "^3.0.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jest": "^22.1.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.5.1",
"eslint-plugin-react-hooks": "^1.6.0",
"eventsource-polyfill": "^0.9.6",
"extract-text-webpack-plugin": "^3.0.0",
"faker": "^4.1.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"husky": "^1.1.3",
"inject-loader": "^3.0.0",
"jest": "^23.6.0",
"node-notifier": "^5.1.2",
"node-sass": "^4.7.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"phantomjs-prebuilt": "^2.1.14",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"react-jss": "^8.6.1",
"react-test-renderer": "^16.6.0",
"react-text-mask": "^5.1.0",
"regenerator-runtime": "^0.12.1",
"rimraf": "^2.6.0",
"sass-loader": "^6.0.6",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"style-loader": "^0.19.0",
"text-mask-addons": "^3.7.1",
"url-loader": "^0.5.8",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
build.js
'use strict';
require('./check-versions')();
process.env.NODE_ENV = 'production';
const ora = require('ora');
const rm = require('rimraf');
const path = require('path');
const chalk = require('chalk');
const webpack = require('webpack');
const config = require('../config');
const webpackConfig = require('./webpack.prod.conf');
const spinner = ora('building...');
spinner.start();
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err;
webpack(webpackConfig, function (err, stats) {
spinner.stop();
if (err) throw err;
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n');
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'));
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'));
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
});
webpack.prod.conf.js
const paths = require('./paths');
const utils = require('./utils');
const webpack = require('webpack');
const config = require('../config');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: require('../config/prod.env');
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].js'),
chunkFilename: utils.assetsPath('js/[id].js')
},
resolve: {
alias: {
settings: `${paths.settings}/dist.js`
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
// UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].css'),
// set the following option to `true` if you want to extract CSS from
// codesplit chunks into this main css file as well.
// This will result in *all* of your app's CSS being loaded upfront.
allChunks: false,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,
host: '@_host_@',
template: 'index.html',
inject: false,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks(module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(paths.nodeModules) === 0
);
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: paths.static,
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
]),
// copy any extra assets to root dist
new CopyWebpackPlugin([
{
from: `${paths.root}\\web.config`,
to: config.build.dist,
ignore: ['.*']
}
])
]
});
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin');
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
`\\.(${
config.build.productionGzipExtensions.join('|')
})$`
),
threshold: 10240,
minRatio: 0.8
})
);
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
module.exports = webpackConfig;
webpack.base.conf
const paths = require('./paths');
const utils = require('./utils');
const config = require('../config');
module.exports = {
context: paths.root,
entry: {
app: './src/main.jsx'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'@': paths.src,
api: paths.api,
settings: `${paths.settings}/local.js`,
enums: paths.enums
}
},
externals: {
bamboraCheckout: 'customcheckout'
},
module: {
rules: [
...(config.dev.useEslint ? [{
test: /\.js$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [paths.src, paths.test],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
}] : []),
{
test: /\.(js|jsx|mjs)$/,
loader: 'babel-loader',
include: [paths.src, paths.test]
},
{
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]')
}
}
]
}
};
dev.env.js
'use strict';
const merge = require('webpack-merge');
const prodEnv = require('./prod.env');
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
});
prod.env.js
'use strict';
module.exports = {
NODE_ENV: '"production"'
};