Eve*_*tss 8 javascript reactjs webpack isomorphic-javascript react-starter-kit
在同构反应应用程序中我myModule
应该在节点和浏览器环境中表现不同.我想配置此分割点的package.json
用于myModule
:
package.json
{
"private": true,
"name": "myModule",
"main": "./myModule.server.js",
"browser": "./myModule.client.js"
}
Run Code Online (Sandbox Code Playgroud)
file structure
??? myModule
? ??? myModule.client.js
? ??? myModule.server.js
? ??? package.json
?
??? browser.js
??? server.js
Run Code Online (Sandbox Code Playgroud)
因此,当我myModule
在节点中使用时,我应该只得到myModule.server.js
:
server.js
import myModule from './myModule';
myModule(); // invoke myModule.server.js
Run Code Online (Sandbox Code Playgroud)
在浏览器端应该只使用 myModule.client.js
以下内容构建bundle:
browser.js
import myModule from './myModule';
myModule(); // invoke myModule.client.js
Run Code Online (Sandbox Code Playgroud)
react-starter-kit使用这种方法,但我无法弄清楚这个配置的定义.
package.json
做这种分裂是很好的语义点.myModule.client.js
.你可以有这种文件结构:
??? myModule
? ??? myModule.client.js
? ??? myModule.server.js
? ??? index.js <-- difference
?
??? browser.js
??? server.js
Run Code Online (Sandbox Code Playgroud)
并在index.js
:
if (process.browser) { // this condition can be different but you get the point
module.exports = require('./myModule.client');
} else {
module.exports = require('./myModule.server');
}
Run Code Online (Sandbox Code Playgroud)
这个问题的主要问题是客户端包含有大量繁重的后端代码.
我包括我的webpack.config.js
.奇怪的是,这个配置始终指向myModule.client.js
浏览器和节点.
const webpack = require('webpack');
var path = require('path');
var fs = require('fs');
const DEBUG = !process.argv.includes('--release');
const VERBOSE = !process.argv.includes('--verbose');
const AUTOPREFIXER_BROWSERS = [
'Android 2.3',
'Android >= 4',
'Chrome >= 35',
'Firefox >= 31',
'Explorer >= 9',
'iOS >= 7',
'Opera >= 12',
'Safari >= 7.1',
];
let nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1 ;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
let loaders = [
{
exclude: /node_modules/,
loader: 'babel'
},
{
test: [/\.scss$/,/\.css$/],
loaders: [
'isomorphic-style-loader',
`css-loader?${DEBUG ? 'sourceMap&' : 'minimize&'}modules&localIdentName=` +
`${DEBUG ? '[name]_[local]_[hash:base64:3]' : '[hash:base64:4]'}`,
'postcss-loader?parser=postcss-scss'
]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: 'url-loader',
query: {
name: DEBUG ? '[name].[ext]' : '[hash].[ext]',
limit: 10000,
},
},
{
test: /\.(eot|ttf|wav|mp3)$/,
loader: 'file-loader',
query: {
name: DEBUG ? '[name].[ext]' : '[hash].[ext]',
},
},
{
test: /\.json$/,
loader: 'json-loader',
},
];
const common = {
module: {
loaders
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
],
postcss: function plugins(bundler) {
var plugins = [
require('postcss-import')({ addDependencyTo: bundler }),
require('precss')(),
require('autoprefixer')({ browsers: AUTOPREFIXER_BROWSERS }),
];
return plugins;
},
resolve: {
root: path.resolve(__dirname, 'src'),
extensions: ['', '.js', '.jsx', '.json']
}
};
module.exports = [
Object.assign({} , common, { // client
entry: [
'babel-polyfill',
'./src/client.js'
],
output: {
path: __dirname + '/public/',
filename: 'bundle.js'
},
target: 'web',
node: {
fs: 'empty',
},
devtool: DEBUG ? 'cheap-module-eval-source-map' : false,
plugins: [
...common.plugins,
new webpack.DefinePlugin({'process.env.BROWSER': true }),
],
}),
Object.assign({} , common, { // server
entry: [
'babel-polyfill',
'./src/server.js'
],
output: {
path: __dirname + '',
filename: 'server.js'
},
target: 'node',
plugins: [
...common.plugins,
new webpack.DefinePlugin({'process.env.BROWSER': false }),
],
node: {
console: false,
global: false,
process: false,
Buffer: false,
__filename: false,
__dirname: false,
},
externals: nodeModules,
})
];
Run Code Online (Sandbox Code Playgroud)
行为在这里标准化:https : //github.com/defunctzombie/package-browser-field-spec
尽管该规范是非官方的,但许多 Javascript 打包器都遵循它,包括 Webpack、Browserify 和 React Native 打包器。浏览器字段不仅允许您更改模块入口点,还可以替换或忽略模块中的单个文件。它非常强大。
由于 Webpack 默认为 Web 捆绑代码,如果您想将 Webpack 用于您的服务器构建,您需要手动禁用浏览器字段。您可以使用target
配置选项来做到这一点:https : //webpack.js.org/concepts/targets/
问这个问题已经很长时间了。我只是想澄清以前的答案。
如果您查看 React Starter Kit 中的 tools/webpack.config.js,您会看到它导出了两个略有不同的 Webpack 配置,例如 module.exports = [clientConfig, sererConfig]。服务器端捆绑配置将此字段目标设置为节点(默认情况下它是网络)。
似乎没有记录此 webpack 行为,但是当目标是“节点”时,webpack 会自动获取“主”条目,而当目标是“web”时,它会自动获取“浏览器”条目。
如果您查看React Starter Kit,tools/webpack.config.js
您会发现它导出两个略有不同的 Webpack 配置,例如. 服务器端捆绑配置将此字段设置为(默认情况下为)。module.exports = [clientConfig, sererConfig]
target
node
web
https://webpack.github.io/docs/configuration.html#target
您描述的方法非常适合具有完全相同的 API 但不同实现的模块,例如在浏览器特定实现中使用 HTTP 客户端实用程序以及在其服务器实现中使用XMLHttpRequest
Node模块的情况:http
https://github.com/kriasoft/react-starter-kit/tree/master/src/core/fetch