How can I share webpack.config snippets between projects? - npm

I have several webpack configurations with very similar webpack.config files. I like to put webpack.config parts in a shared module that (I include the shared module with "npm link"), but that doesn't work as can't find dependencies, like "webpack" as it's the first dependency it encounters.
17 07 2017 14:49:32.694:ERROR [config]: Invalid config file!
Error: Cannot find module 'webpack'
at Function.Module._resolveFilename (module.js:470:15)
First webpack.config lines:
const webpack = require('webpack');
const path = require('path');
....
How can I instruct webpack to search for the included dependences in node_modules of the project that includes the webpack.config?
I tried to realise this by adding the following to the resolve webpack.config section, but that doesn't help:
modules: [path.resolve(__dirname, "node_modules"), "node_modules"]
I think it's not used by the webpack.config itself but by the JS code that is processed by webpack.config.

I solved it by passing in required root dir as argument to the common webpack config, and use that to change the __dirname variable that is used to find plugins and other stuff.
In code:
The webpack.config.js:
const path = require('path');
const loader = require('lodash/fp');
const common = require('bdh-common-js/etc/webpack/webpack.config.common');
module.exports = function (env) {
if (env === undefined) {
env = {};
}
env.rootdir = __dirname; // Add the root dir that can be used by the included webpack config.
const result = loader.compose(
function () {
return common(env)
}
// Any other "fragments" go here.
)();
// Customize the webpack config:
result.entry = {
entry: ['./src/entry.js', './src/js/utils.js'],
}
result.resolve.alias.Context = path.resolve(__dirname, 'src/js/context');
...... more stuff..
return result;
}
And the common webpack.config part that receives the argument:
module.exports = function (env) {
if (env !== undefined) {
if (env.rootdir !== undefined) {
__dirname = env.rootdir;
}
}
....
const node_modules = path.resolve(__dirname, 'node_modules');
const webpack = require(node_modules + '/webpack');
const CleanWebpackPlugin = require(node_modules + '/clean-webpack-plugin');
....
}

Related

run vue3 ssr on cloudflare workers

I'm trying to run a vue ssr app on cloudflare workers.
I generated a new project using wrangler generate test
I installed vue using npm install vue#next and npm install #vue/server-renderer
I edited the index.js file like this:
const { createSSRApp } = require('vue')
const { renderToString } = require('#vue/server-renderer')
const app = createSSRApp({
data: () => ({ msg: 'hello' }),
template: `<div>{{ msg }}</div>`
})
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const html = await renderToString(app)
return new Response(html, {status: 200})
}
I then used wrangler dev to test it, but when I access the page I get this error:
ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined
at Module.<anonymous> (worker.js:8:104768)
at n (worker.js:1:110)
at Object.<anonymous> (worker.js:8:104943)
at n (worker.js:1:110)
at worker.js:1:902
at worker.js:1:912
Any help or guidance is appreciated
I faced similar issue and was able to fix it by defining a global constant (VUE_PROD_DEVTOOLS = false) during compile time.
Here is how my webpack prod config looks like:
const webpack = require('webpack');
const { merge } = require("webpack-merge");
const webpackCommon = require("./webpack.common");
const prodConfig = {
mode: 'production',
plugins: [
new webpack.DefinePlugin({
__VUE_PROD_DEVTOOLS__: JSON.stringify(false)
}),
]
};
module.exports = merge(webpackCommon, prodConfig);

ISO proper way to chain Webpack via vue.config.js to add global .scss imports to my .vue files (vue-cli-plugin-nativescript-vue)

I have Vue.js project I've setup previously that dynamically adds defined .scss files to my .vue template files, so I can access my variables, mixins, etc. in the templates without #importing them, or having them duplicate code from imports.
My problem is I'm setting up a NativeScript/Vue.js project with vue-cli-plugin-nativescript-vue and was curious if anyone has successfully setup their webpack to allow the same functionality. It's my understanding that the plugin replaces webpack with the latest when you run, as specified in the docs https://cli.vuejs.org/guide/webpack.html#replacing-loaders-of-a-rule.
Below is my vue.config.js (which compiles with no error) but doesn't seem to be working. I'm probably missing something or don't understand exactly how this is working, any help is appreciated.
const path = require('path')
module.exports = {
chainWebpack: config => {
const ofs = ['vue-modules', 'vue', 'normal-modules', 'normal']
const cssRules = config.module.rule('css')
const postRules = config.module.rule('postcss')
const addSassResourcesLoader = (rules, type) => {
rules
.oneOf(type)
.use('sass-resoureces-loader')
.loader('sass-resources-loader')
.options({
resources: './src/styles/_global.scss', // your resource file or patterns
})
}
ofs.forEach(type => {
addSassResourcesLoader(cssRules, type)
addSassResourcesLoader(postRules, type)
})
return config
},
}
Vue CLI provides a config to augment your CSS loaders:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
scss: {
// sass-loader#^8.0.0
prependData: `import "~#/styles/_global.scss";`,
// sass-loader#^9.0.0 or newer
additionalData: `import "~#/styles/_global.scss";`,
}
}
}
}

How do you enable source maps in Webpack?

I want to enable source maps in my webpack.config.js. I'm adding onto some opensource and their webpack.config.js looks weird.
webpack.config.js
// Entry point webpack config that delegates to different environments depending on the --env passed in.
module.exports = function(env) {
process.env.NODE_ENV = env;
return require(`./webpack.${env}.js`);
};
Here is what it returns if env = development
/**
* Webpack configuration for development.
*
* Contains plugins and settings that make development a better experience.
*/
const webpack = require("webpack");
const merge = require("webpack-merge");
const fs = require("fs");
const { execSync } = require("child_process");
const path = require("path");
const argv = require("yargs").argv;
const commonConfig = require("./webpack.common.js");
const DashboardPlugin = require("webpack-dashboard/plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
if (!fs.existsSync(path.resolve(__dirname, "vendor", "vendor-manifest.json"))) {
// This _should_ exist, since we run the command for you when you run `npm run dev`
console.log(
"Vendor files not found. Running 'npm run build:dev-dll' for you..."
);
execSync("npm run build:dev-dll");
console.log("Done generating vendor files.");
}
const devConfig = {
mode: "development",
main: {
devtool: "source-map",
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify("development")
}),
new webpack.DllReferencePlugin({
context: ".",
manifest: require("./vendor/vendor-manifest.json")
}),
new ForkTsCheckerWebpackPlugin({
tslint: true,
async: false,
silent: true
})
]
}
};
// Only enable the dashboard plugin if --watch is specified
// The dashboard plugin annoyingly doesn't allow webpack to exit,
// so we only enable it with --watch, which doesn't exit anyways
if (argv.watch) {
devConfig.main.plugins.push(new DashboardPlugin());
}
module.exports = merge.multiple(commonConfig, devConfig);
I don't know if source map should be added to webpack.config.js or maybe just the development version and I don't know how to add it cause these config files look odd to me.
The line... "devtool": "source-map" is correct, but it appears to be at the wrong depth.
Should be:
const devConfig = {
mode: "development",
devtool: "source-map",
main: {
...
}
};

Entry point - webpack.config.js vs vue.config.js

In the webpack.config.js file we can set entry file as below.
module.exports = (env = {}, argv = {}) => {
const config = {
entry: {
main: './src/js/main.js'
},
}
}
But in vue.config.js file, how to declare the entry file? I have checked in doc. but there is property such that.
Vue CLI 3 integrates the webpack-chain library as another way of configuring webpack.
For example, your config file may look like:
chainWebpack: config => {
// clear the existing entry point
config
.entry('main')
.clear()
// add your custom entry point
config
.entry('main')
.add('./src/js/main.js')
}
See the section on config entryPoints.
For vue-cli 4 it's:
chainWebpack: (config) => {
// Clear the existing entry point
config.entry('app').clear()
// Add the custom entry point
config.entry('app').add('./src/js/main.js')
}

Native support for ES6 in PhantomJS

is there a way to make PhantomJS natively support ES6, I have a bunch of ES6 code which is converted to ES5 via Babel, what I need to accomplish is accurate measurement of code coverage which is done for ES6 code rather than ES5. It's a requirement from client, so I can't just tell him to stop requesting such thing...
Afaik NodeJS already has native support for ES6, is there a way to do that with PhantomJS?
I've ended up using raw NodeJS (without PhantomJs) + Express + JSDom (https://github.com/tmpvar/jsdom), the POC looks like this:
"use strict"
const $module = require('module');
const path = require('path');
const babel = require("babel-core");
const Jasmine = require('jasmine');
const reporters = require('jasmine-reporters');
const express = require('express');
const jsdom = require("jsdom");
const app = express();
const vm = require('vm');
const fs = require("fs");
app.get('/', function (req, res) {
res.sendFile('index.html', { root: __dirname });
});
app.use('/bower_components', express.static('bower_components'));
const load = function (filename) {
return fs.readFileSync(`./bower_components/${filename}`, "utf-8");
};
const packages = [
fs.readFileSync('./bower_components/jquery/dist/jquery.js', "utf-8"),
fs.readFileSync('./bower_components/angular/angular.js', "utf-8"),
fs.readFileSync('./bower_components/angular-mocks/angular-mocks.js', "utf-8")
];
const sut = {
'./js/code.js': fs.readFileSync('./js/code.js', "utf-8")
};
const tests = {
'./tests/test.js': fs.readFileSync('./tests/test.js', "utf-8")
};
function navigate(FakeFileSystem, root, cwd, filename) {
// Normalize path according to root
let relative = path.relative(root, path.resolve(root, cwd, filename));
let parts = relative.split(path.sep);
let iterator = FakeFileSystem;
for (let part of parts) {
iterator = iterator[part] || (iterator[part] = { });
}
return iterator;
}
const server = app.listen(3333, function () {
const host = server.address().address;
const port = server.address().port;
const url = `http://${host === '::' ? 'localhost' : host}:${port}`;
console.log(`Server launched at ${ url }`);
console.log(`Running tests...`)
jsdom.env({
url: url,
src: packages,
done: function (err, window) {
let jasmine = new Jasmine();
let FakeFileSystem = {};
let descriptors = [];
jasmine.configureDefaultReporter({ showColors: true });
let env = jasmine.env;
for (let propertyName in env) {
if (env.hasOwnProperty(propertyName)) {
window[propertyName] = env[propertyName];
}
}
let context = vm.createContext(window);
let collections = [sut, tests];
for (let collection of collections) {
for (let filename in collection) {
let descriptor = navigate(FakeFileSystem, __dirname, '.', filename);
let source = collection[filename];
let transpiled = babel.transform(source, { "plugins": ["transform-es2015-modules-commonjs"] });
let code = $module.wrap(transpiled.code);
let _exports = {};
let _module = { exports: _exports };
descriptor.code = vm.runInContext(code, context);
descriptor.module = _module;
descriptor.exports = _exports;
descriptor.filename = filename;
descriptors.push(descriptor);
}
}
for (let descriptor of descriptors) {
let cwd = path.dirname(path.relative(__dirname, descriptor.filename));
descriptor.code.call(
undefined,
descriptor.exports,
// Closure is used to capture cwd
(function (cwd) {
return function (filename) { // Fake require function
return navigate(FakeFileSystem, __dirname, cwd, filename).exports;
}
})(cwd),
descriptor.module,
descriptor.filename
);
}
jasmine.execute();
server.close();
}
});
});
The beauty of this approach is that there is no need in transpiling code with babel, it allows frontend packages such as Angular to get loaded from bower, while all the config stuff comes from npm...
EDIT
I've stumbled upon the fact that NodeJS doesn't support all ES6 features yet, and such feature as ES6 modules is a real pain, they aren't supported anywhere, so I've ended up with doing partial transpilation of code with babel, with the expectation that as NodeJS will start providing richer and richer support for ES6 I will eventually turn-off babel features step by step and switch to native support when it will become available...