I have the following configuration file for Cucumber:
const common = {
// ...common settings here
};
module.exports = {
ci: {
...common,
format: [
"progress",
],
},
default: {
...common,
format: [
"progress-bar",
],
},
};
This works flawlessly. I can specify any of the defined profiles, etc. I'm looking migrate, if possible, the same configuration file into ESM format, but I just don't quite understand how to make the default profile work. If I do:
export default {
ci: { /* ... */ },
default: { /* ... */ },
};
...and place "type": "module" in package.json, it stops working and the configuration is not understood anymore.
Can anyone spot what's the catch there? Would be great a small explanation if this can be done :)
I was initially confused by the default keyword ;)
This is a working (ESM) configuration with multiple profiles:
const common = {
/* ... */
};
export const ci = {
...common,
format: [
"progress",
],
};
export default {
...common,
format: [
"progress-bar",
],
};
Related
I'm attempting to package with webpack. However, I am receiving a Module parse failed: Unexpected token error. It points to a node module, which has a export statement using an astrisk.
export * as example from "exampleModule";
How can I avoid webpack throwing the error when building?
I'm using babel 7.11.5 and have plugin-proposal-export-namespace-from in my babel config plugins.
My babel.config.js is as follows:
/* eslint global-require: off, import/no-extraneous-dependencies: off */
const developmentEnvironments = ['development', 'test'];
const developmentPlugins = [require('react-hot-loader/babel')];
const productionPlugins = [
require('babel-plugin-dev-expression'),
// babel-preset-react-optimize
require('#babel/plugin-transform-react-constant-elements'),
require('#babel/plugin-transform-react-inline-elements'),
require('babel-plugin-transform-react-remove-prop-types'),
];
module.exports = (api) => {
// See docs about api at https://babeljs.io/docs/en/config-files#apicache
const development = api.env(developmentEnvironments);
return {
presets: [
// #babel/preset-env will automatically target our browserslist targets
require('#babel/preset-env'),
require('#babel/preset-typescript'),
[require('#babel/preset-react'), { development }],
],
plugins: [
// Stage 0
require('#babel/plugin-proposal-function-bind'),
// Stage 1
require('#babel/plugin-proposal-export-default-from'),
require('#babel/plugin-proposal-logical-assignment-operators'),
[require('#babel/plugin-proposal-optional-chaining'), { loose: false }],
[
require('#babel/plugin-proposal-pipeline-operator'),
{ proposal: 'minimal' },
],
[
require('#babel/plugin-proposal-nullish-coalescing-operator'),
{ loose: false },
],
require('#babel/plugin-proposal-do-expressions'),
// Stage 2
[require('#babel/plugin-proposal-decorators'), { legacy: true }],
require('#babel/plugin-proposal-function-sent'),
require('#babel/plugin-proposal-export-namespace-from'),
require('#babel/plugin-proposal-numeric-separator'),
require('#babel/plugin-proposal-throw-expressions'),
// Stage 3
require('#babel/plugin-syntax-dynamic-import'),
require('#babel/plugin-syntax-import-meta'),
[require('#babel/plugin-proposal-class-properties'), { loose: true }],
require('#babel/plugin-proposal-json-strings'),
...(development ? developmentPlugins : productionPlugins),
],
};
};
Thanks to dotenv I can use environment variables in my nuxt.config.js file
Only I have whole settings that need to disappear depending on the environment. In some cases, I know how to use a tertiary condition, but in others, I cannot.
For example, for my dev environment, I have to do this :
export default {
head: {
title: process.env.APP_NAME,
},
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'#nuxtjs/auth',
'#nuxtjs/dotenv'
],
axios: {
baseURL: 'http://app.test/api',
},
…
}
And for my production environment I have to add some things
export default {
head: {
title: process.env.APP_NAME,
},
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'#nuxtjs/auth',
'#nuxtjs/dotenv',
'#nuxtjs/proxy'
],
axios: {
prefix: '/api/',
proxy: true
},
// also a new bloc
proxy: {
'/api/': {
target: 'https://my-api.app/'
}
},
…
}
How to do that simply?
The Nuxt config file is simply a normal .js file.
You can create and modify the exported object the same as any other object.
const isProd = true;
const nuxtConfig = {
head: {
title: process.env.APP_NAME,
},
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'#nuxtjs/auth',
'#nuxtjs/dotenv'
],
axios: {
baseURL: 'http://app.test/api',
},
};
if(isProd) {
nuxtConfig.modules.push('#nuxtjs/proxy');
nuxtConfig.axios.proxy = true;
nuxtConfig.proxy = {
'/api/': {
target: 'https://my-api.app/'
}
}
}
export default nuxtConfig;
Use inline conditionals
If you only have minimal differences between environments, maintain the default nuxt.config.js structure and just use inline conditions (ie ternary operator) wherever you need.
Example:
head: {
title: process.env.NODE_ENV === 'prod' ? "my prod title" : "my dev title"
}
You can also chain multiple conditions...
head: {
title: process.env.NODE_ENV === 'prod1' ? "my prod title 1" : process.env.NODE_ENV === 'prod2' ? "my prod title 2" : "my dev title"
}
... however now you have more complexity. If it gets too deep, then maybe it's time to have logic outside of the main export object, as
#Jordan suggested.
Is it possible to use a glob or regex pattern for the externals in my rollup config? With this config:
export default {
...
external: [
'prop-types',
'react',
'prettier/standalone',
'prettier/parser-babylon',
'react-syntax-highlighter/prism-light',
'react-syntax-highlighter/languages/prism/jsx',
'react-syntax-highlighter/styles/prism/tomorrow',
'react-element-to-string'
],
...
};
I would like to do something like:
export default {
...
external: [
'prop-types',
'react',
'prettier/**',
'react-syntax-highlighter/**',
'react-element-to-string'
],
...
};
This is not possible at the moment. You can however use a function to achieve something similar:
export default {
...
external(id) {
return [
'prop-types',
'react',
'prettier',
'react-syntax-highlighter',
'react-element-to-string'
].includes(id.split('/')[0]);
},
...
};
You should avoid costly computations in this function as it will be called a lot (once for every import in every file to be precise).
Another option is to add the rollup-pluginutils package as a dependency which contains a createFilter function for glob support:
import { createFilter } from 'rollup-pluginutils';
const external = createFilter([
'prop-types',
'react',
'prettier/**',
'react-syntax-highlighter/**',
'react-element-to-string'
], null, {resolve: false});
// {resolve: false} will make sure these filters are not passed to
// path.resolve first and resolved against the current working directory
export default {
...
external,
...
};
Regex in external is also supported by rollup now, like this:
export default {
external: ['three', /three\/.*/]
}
This will mark three and three/* as externals, I have used in my projects, it works as expected.
Please refer https://rollupjs.org/guide/en/#external for more options.
I have a project with miltiple configuration. The first config is config.dev.js file that contains some development configiration. I using it in development mode. The second config is config.js file. I using it in production mode.
In the code I using imports:
import * as config from './config.js';
I want to use the first config file in development and the second to production whithout rewriting all of the imports. How can I replace this config depending on the build mode?
This is an old question but I've recently stumbled across the same issue and webpack.NormalModuleReplacementPlugin doesn't seem to work anymore (or at least not in my case, where I used JSON files as config). Instead I found another solution using alias:
const path = require("path");
modules.export = {
...
resolve: {
...
alias: {
[path.resolve(__dirname, "src/conf/config.json")]:
path.resolve(__dirname, "src/conf/config.prod.json")
}
}
...
}
I realize this is an old post, but this is one of the first results on Google, so I thought a better answer would be good.
Webpack has a built in "Normal Module Replacement Plugin".
plugins: [
new webpack.NormalModuleReplacementPlugin(
/some\/path\/config\.development\.js/,
'./config.production.js'
)
]
For my use, I put the env file in a variable Here is an example:
let envFilePath = './environment.dev.js';
if (env === 'production') {
envFilePath = './environment.prod.js';
} else if (env === 'staging') {
envFilePath = './environment.stg.js';
}
module.exports = {
// other webpack stuff
....
plugins:[
new webpack.NormalModuleReplacementPlugin(
/src\/environment\/environment\.js/,
envFilePath
),
...
]
}
You can use webpack file-replace-loader
https://www.npmjs.com/package/file-replace-loader
Example:
//webpack.config.js
const resolve = require('path').resolve;
module.exports = {
//...
module: {
rules: [{
test: /\.config\.js$/,
loader: 'file-replace-loader',
options: {
condition: process.env.NODE_ENV === 'development',
replacement: resolve('./config.dev.js'),
async: true,
}
}]
}
}
I wanted to imitate the Angular fileReplacements syntax so I used a config.json like Angular's and if the configuration key matches the env I pass to webpack, loop through the replacements and create several Webpack module rules.
It's not the most elegant thing ever but this is what I ended up with:
// config.json
{
"title": "Some Title",
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},
"lan": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.lan.ts"
}
]
}
}
}
// webpack.config.js
const appConfig = require('./config.json');
module.exports = (env, argv) => {
// env.build is like `ng build --prod` as `webpack --env.build=production`
const configuration = appConfig.configurations[env.build];
const fileReplacements = [];
// Safety Check
if(configuration && configuration.fileReplacements) {
// Iterate through replacements
for(const replacement of configuration.fileReplacements) {
// create Webpack module rule
const replace = {
test: path.resolve(replacement.replace),
loader: 'file-replace-loader',
options: {
replacement: path.resolve(replacement.with),
async: true
}
}
fileReplacements.push(replace);
}
}
return {
mode: //...
entry: //...
module: {
rules: [
{
//...
},
// Unpack anywhere here
...fileReplacements
]
}
}
}
This way you don't have to keep messing with webpack and regex tests, just add to the array in config.json
You can also use babel-loader like this:
//webpack.config.js
const resolve = require('path').resolve;
module.exports = {
//...
module: {
strictExportPresence: true,
rules: [{
test: /\.config\.js$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
plugins: [
[
"module-resolver",
{
resolvePath(sourcePath, currentFile, opts) {
if(process.env.NODE_ENV === 'development') {
return sourcePath.substr(0, sourcePath.lastIndexOf('/')) + '/config.dev.js';
} else {
return sourcePath;
}
}
}
]
]
}
}]
}
}
This way you can even define complex algorithms to determine which file you wanna use.
Another way is to use Webpack.DefinePlugin. Especially useful if you have a tiny code block that you want to be included conditionally.
Example follows:
// webpack.conf.js
// Code block that should be inserted or left blank
const ServiceWorkerReg = `window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});`
appConfig = {
plugins: [
new webpack.DefinePlugin({
__SERVICE_WORKER_REG: isDev ? '' : ServiceWorkerReg,
}),
]
...
}
// Some module index.js
__SERVICE_WORKER_REG
... // other non conditional code
I have the following build profile for a small app:
var profile = (function(){
var copyOnly = function(filename, mid){
/* ..snip.. */
};
return {
basePath: "../../src",
releaseDir: "../dist",
releaseName: "lib",
action: "release",
packages: [
'dojo',
'dijit',
//'dojox',
'amd',
{
name: 'lodash',
location: 'lodash',
trees: [
[".", ".", /(\/\.)|(~$)|(vendor|test)/]
]
},
{
name: 'd3',
location: 'd3',
main: 'd3.min',
trees: [
[".", ".", /(\/\.)|(~$)|(src|lib|test)/]
]
},
{ name: 'app', location: 'app' }
],
layers: {
"dojo/dojo": {
include: [ "dojo/dojo", "amd/d3","amd/gmaps",
"app/main", "app/run" ],
customBase: true,
boot: true
}
},
resourceTags: {
/* ..snip.. */
}
};
})();
The problem is this: all I need is the lodash.min.js file to be processed by the Dojo build system. Unfortunately, when you include a package definition in your profile, the build system looks at all files in the relevant directory using an implicit trees value. You can overwrite it (as I have done here) and add some ignore directives, but this is ugly and leaves you open to missing something of. What I'd like to do is affirmatively indicate precisely which file(s) that I'm interested in processing for my build process.
Does Dojo allow you to do this? The documentation is a little scant in this area, but if you can help me find a resource that explains this more clearly, that would be great!
As of 1.9 at least, I believe this can be done:
// ... snip ...
{
name:'lodash',
location:'lodash',
trees:[],
dirs:[],
files:[
["lodash.min.js"]
]
},
This explicitly lists the files, while also squashing implicit tree and directory discovery.
My belief here is based on a cursory review of util/build/discover.js -- but as I read the documentation files only should be supported.